How to send data to Service Bus Topic with Azure Functions? - c#

I have default C# based HTTP Trigger here and I wish to send data "Hello Name" to Service Bus Topic (already created). I'm coding at portal.
How to do it Service Bus output binding?
This is not working. Any help available?
-Reference missing for handling Service Bus?
-How to define Connection of service bus? Where is Functions.json
-How to send a message to service bus?
//This FunctionApp get triggered by HTTP and send message to Azure Service Bus
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Company.Function
{
public static class HttpTriggerCSharp1
{
[FunctionName("HttpTriggerCSharp1")]
[return: ServiceBus("myqueue", Connection = "ServiceBusConnection")] // I added this for SB Output. Where to define.
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
// I added this for SB Output
return responseMessage;
}
}
}

Firstly, there are two bindings to send data to service bus. Firstly is what you show, using the return binding, after install two packages Microsoft.Azure.WebJobs.Extensions.ServiceBus and WindowsAzure.ServiceBus, then you will be able to send data. And you could not do it cause your function type is IActionResult and you are trying to return string(responseMessage).
So if you want to send the whole responseMessage, just return new OkObjectResult(responseMessage);, it will work. And the result would be like below pic.
And if you want to use return responseMessage; should change your method type to string, it will be public static async Task<string> RunAsync and result will be below.
Another binding you could refer to below code or this sample.
[FunctionName("Function1")]
[return: ServiceBus("myqueue", Connection = "ServiceBusConnection")]
public static async Task RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[ServiceBus("myqueue", Connection = "ServiceBusConnection")] MessageSender messagesQueue,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
byte[] bytes = Encoding.ASCII.GetBytes(responseMessage);
Message m1 = new Message(bytes);
await messagesQueue.SendAsync(m1);
}
How to define Connection of service bus? Where is Functions.json
In the local you should define the connection in the local.settings.jon, you could use any name with the connection, then in the binding Connection value should be the name you set in the json file. And cause you are using c#, so you could not modify the function.json file, there will be a function.json file in the debug folder. So you could only change the binding in the code.
Hope this could help you, if you still have other problem , please feel free to let me know.

Make sure you first install Microsoft.Azure.WebJobs.Extensions.ServiceBus NuGet package. Then make sure you are using it in your project:
using Microsoft.Azure.WebJobs.Extensions.ServiceBus;
Make sure you clean and build the project to make sure you have no errors.
Then you need to make sure you have a "ServiceBusConnection" connection string inside your local.settings.json file:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"ServiceBusConnection": "Endpoint=sb://...",
}
}
Which you can get if you go to Azure portal -> Service bus namespace -> Shared access policies -> RootManageSharedAccessKey -> Primary Connection String. Copy and paste this connection string inside "ServiceBusConnection". You can also use the Secondary Connection String as well.
Note: Service bus queues/topics have shared access policies as well. So if you don't want to use the Service bus namespace level access policies, you can create one at queue/topic level, so you your function app only has access to the queue/topic defined in your namespace.
Also if you decide to publish your function app, you will need to make sure you create a configuration application setting for "ServiceBusConnection", since local.settings.json is only used for local testing.

Related

How to create Http Trigger and Time Trigger in one azure function in C#?

I have this
It has http trigger and time trigger.
Now when I run the azure function it gives me this
What am I doing wrong ?
(EDIT)
Just updated my visual studio and build tools to latest version and it solve the problem.
Turns out my visual studio and build tools were outdated.
So I just updated it the latest version and it solved my issue.
Thank you for all the answers.
I have taken .NET 6 Azure Functions v4 and made the Function 2 (Timer Trigger as static) and changed the Run method name to Run2, it is working successfully as you can see below screenshot:
And in 2nd practical, tried with your Timer Trigger Code Provided, made changes as did in above with Authorization Level as Function and got the successful result:
Function Code:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace KrishNet6FunApp1040
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
[FunctionName("TimerTriggerCSharp")]
public static void Run2([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
{
if (myTimer.IsPastDue)
{
log.LogInformation("Timer is running late!");
}
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}
}
}

Error (RequestDisallowedByPolicy): Resource XXX was disallowed by policy(...Require a tag on resources...)

I am proceeding with the publication of a function in azure. When creating the "Function App" from the wizard I have the following error: "... Require a tag on resources ..."
Error:
I am suspecting that most likely I should add some "tags" that are required for the creation of the "Function App". If I'm correct, how could I configure that from my c # code?
Here I attach the code of my function. How could I assign the values ​​of the tags that the assigned policies request me from my code in c #?
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
It seems the problem is from your work group's policy.
Search Policy on portal, navigate to Definition to check if your subscription set this policy: Require a tag on resources, which Enforces existence of a tag. Find out what the tag name is needed, such as 'Region'.
The solution:
Add the tag when you create your Function app. Such as: "Region":"centralus"

How I can access all fields of a http-request in an azure function (parse JSON in C#)?

The microsoft azure is for me complete new programming topic.
Programming base language is C#.
I have to use Azure Funtion Http trigger from logic App (when new e-mail arrive).
I give all possible data from the incoming e-mail in the log app to
to the azure function call.
Then I had first the problem nothing (no data) was requestable from the HttpRequest req.
I found out that C# .NetCore3.1 has problem with JSON-Object and get null-object back.
Then I build the project with .NetCore2.1 and it worked generally.
I get correct informations like req.Host and i see a vaild JSON-object in data after such a call
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
But I don't know how I an parse the data like (from, to, subject, content, attachment,..) from the JSON-object.
I have tried many samples i found , but i fond nothing what worked, e.g. get null, exception,..
Can please someone here post a small code snippet that works for azure function compiled with VS2017/2019 .NetCore2.1..
And other question is there eventually a way get the MimeMessage-obj direct from the http-request?
then i can get the informations direct from that object, but helping me with one of this both solution
where fine.
Otherwise I spilit the the JSoN Structure on myself to get the the informations on a very awkward way.
So I hope someone can help me.
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation($" host : {req.Host}");
string name = req.Query["name"];
// read the contents of the posted data into a string
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
// use Json.NET to deserialize the posted JSON into a C# dynamic object
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
For Example i had such a Json-content (is in dtaa after thes 2 lines of code):
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
Json-Content for a short email to parse (other request could differn in more ore lesser paramters(fields))
{ {
"Conversion Id": "AAQkADRmZDAwMTMwLTI3MTMtNGI0Ny1iMzFiLTQzYWJiZDY0YWI1ZQAQAE2OZM06t0uQqpd9MuONKNQ=",
"From": "test1#testxyz.com",
"Has Attachment": false,
"Internet Message Id": "<AM0PR07MB44178000A0B37882D6BC01D99ACC0#AM0PR07MB4417.eurprd07.prod.outlook.com>",
"Is Html": false,
"Is rRad": false,
"Message Id": "AAMkADRmZDAwMTMwLTI3MTMtNGI0Ny1iMzFiLTQzYWJiZDY0YWI1ZQBGAAAAAAAvlJZPJxnGS4f6YWxh7zGsBwBnLziSnuG8R6h5C2SVmlYlAAHViSWpAACAWl3JfUo4SI7D5g-MgfEiAAJiPJQeAAA=",
"Received Time": "2020-12-09T14:05:06+00:00",
"Subject": "test1",
"To": "test2#testxyz.com",
"emailBody": "1234\r\n",
"importance": "normal"
}
}
For this requirement, you need to create an inner class in your function code to parse the request body to an object. Please refer to my code below:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace FunctionApp2
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
//dynamic data = JsonConvert.DeserializeObject(requestBody);
EmailItem data = JsonConvert.DeserializeObject<EmailItem>(requestBody);
log.LogInformation(data.From);
log.LogInformation(data.Has_Attachment.ToString());
return new OkObjectResult("completed");
}
}
public class EmailItem
{
public string From { get; set; }
public Boolean Has_Attachment { get; set; }
//Add other fields which you want, please note add all of the fields which your request may contains in this inner class.
}
}
As you mentioned other request could differn in more ore lesser paramters(fields), so please add all of the fields which your request may contains in the EmailItem class.
By the way, the code I provided above was test with .net core 2.1 as you required. But I think the code can also work in .net core 3.1

Azure function is not logging custom events, dependencies to app insights

We have a Azure Function V3 developed in C#. We tried to log some custom events, dependencies, etc to Azure Application Insights. We are not able to log in app insights using TelemetryClient. The code runs fine without any errors. Also, could see instrumentation key retrieved from config file. However Ilogger logs can be found in app insights traces table. Please find below code that we used,
public class CommunityCreate
{
private readonly TelemetryClient telemetryClient;
public CommunityCreate(TelemetryConfiguration telemetryConfiguration)
{
this.telemetryClient = new TelemetryClient(telemetryConfiguration);
}
[FunctionName("Function1")]
[return: ServiceBus("sample", Connection = "ServiceBusProducerConnection")]
public async Task<string> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "Account/{id:int?}")] HttpRequest req, string id, ILogger log)
{
//log.LogInformation("C# HTTP trigger function processed a request.");
DateTime start = DateTime.UtcNow;
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
var evt = new EventTelemetry("Function called");
evt.Context.User.Id = name;
this.telemetryClient.TrackEvent(evt);
// Generate a custom metric, in this case let's use ContentLength.
this.telemetryClient.GetMetric("contentLength").TrackValue(req.ContentLength);
// Log a custom dependency in the dependencies table.
var dependency = new DependencyTelemetry
{
Name = "GET api/planets/1/",
Target = "swapi.co",
Data = "https://swapi.co/api/planets/1/",
Timestamp = start,
Duration = DateTime.UtcNow - start,
Success = true
};
dependency.Context.User.Id = name;
this.telemetryClient.TrackDependency(dependency);
telemetryClient.TrackEvent("Ack123 Recieved");
telemetryClient.TrackMetric("Test Metric", DateTime.Now.Millisecond);
return name;
}
}
Please make sure you're using the correct packages as below:
Microsoft.Azure.WebJobs.Logging.ApplicationInsights, version 3.0.18
and
update the package Microsoft.NET.Sdk.Functions the latest version 3.0.9.
If you're running the project locally, please add the APPINSIGHTS_INSTRUMENTATIONKEY in local.settings.json, like below:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "xxxx",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "xxx"
}
}
Or if you're running it on azure portal, please configure the Application insights with azure function.
Then I tested your code, the custom events or dependency are correctly logged into Application insights. Here is the screenshot:
If you still have the issue, please let me know(and please also provide more details).

azure function c# http trigger blob output

Can someone describe me how I can configure a C# azure function which uses an HTTP input trigger and a blob storage output trigger?
Maybe also with an example code snippet and an example function.json. I don't get it to work locally with the azure functions core tools.
This is a combined HTTP triggered function with a output blob binding:
[FunctionName("HttpTriggeredFunction")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest httpRequest,
[Blob("blobcontainer", Connection = "StorageConnectionString")] CloudBlobContainer outputContainer,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
await outputContainer.CreateIfNotExistsAsync();
var requestBody = await new StreamReader(httpRequest.Body).ReadToEndAsync();
var blobName = Guid.NewGuid().ToString();
var cloudBlockBlob = outputContainer.GetBlockBlobReference(blobName);
await cloudBlockBlob.UploadTextAsync(requestBody);
return new OkObjectResult(blobName);
}
It uses the CloudBlobContainer output type to get a reference to the blob container which then enables you to use methods such as .GetBlockBlobReference("blobPath") to get a reference to a blob.
Once you have a reference to a blob, you can use different methods to upload:
cloudBlockBlob.UploadFromByteArrayAsync()
cloudBlockBlob.UploadFromFileAsync()
cloudBlockBlob.UploadTextAsync()
cloudBlockBlob.UploadFromStreamAsync()
To get it running locally, you need set some things up. Notice in my example the attribute [Blob("blobcontainer", Connection = "StorageConnectionString")]
"blobcontainer" this can be whatever you want and will be the name of the container that will be created in your storage account by this line outputContainer.CreateIfNotExistsAsync(); (if it doesn't exist already).
Connection = "StorageConnectionString" this can be a setting in your local.settings.json for the connection string of your storage account. When developing locally I would recommend setting this to "UseDevelopmentStorage=true" so that you can take advantage of the storage emulator. Then when you are ready to deploy onto Azure, you would create a setting in the function app containing the real connection string.
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"StorageConnectionString": "UseDevelopmentStorage=true"
}
}
to make an http function that saves to Blob Storage use this code:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log,TextWriter outputBlob)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
outputBlob.WriteLine(requestBody);
string result = "{ 'result': 'ok' }";
dynamic data = JsonConvert.DeserializeObject(result);
return new OkObjectResult(data);
}
You need to set the output binding:
You can then run a test posting content on the test window
Everything you need is there in the Official docs page,
(i) Http and WebHooks
(ii)Output binding blob storage
Http Trigger Sample code
[FunctionName("HttpTriggerCSharp")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
HttpRequest req, ILogger log)
Blob Storage Output binding
[FunctionName("ResizeImage")]
public static void Run(
[BlobTrigger("sample-images/{name}")] Stream image,
[Blob("sample-images-sm/{name}", FileAccess.Write)] Stream imageSmall,
[Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageMedium)

Categories

Resources