I am working on an azure function V2 that peeks the messages from the service bus.
In this function I would like to know the state of the messages (Active, Deferred, Scheduled)
I know that Microsoft.ServiceBus.Messaging.BrokeredMessage has a State property.
But I am using Microsoft.Azure.ServiceBus. So How do I get the state of Microsoft.Azure.ServiceBus.Message?
Just an example function that explains my need:
[FunctionName("GetStates")]
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "getstates")] HttpRequest req, ILogger log)
{
var result = new Dictionary<string, int>() /** string: state, int: counter **/
receiver = new MessageReceiver("MyConnectionString", EntityNameHelper.FormatSubscriptionPath("MyTopic", "MySubscription"));
var messages = await receiver.PeekBySequenceNumberAsync(receiver.LastPeekedSequenceNumber, 50);
// How to get the states???
return new OkObjectResult(result);
}
When the BrokeredMessage type from track 0 SDK was moved to the Message type in track 1 (Microsoft.Azure.ServiceBus), the MessageState was not implemented. While I don't know the rationale behind that decision or wherever this was just missed out by mistake. You could raise an issue with the Azure SDK using the Azure SDK repository issue tracker here.
Related
I have an Azure Durable function (.NET 6) triggered with httpTrigger, I'm trying to prevent start of the function based on the parameters received in the http request.
The code I tried so far :
[FunctionName(nameof(StartOrchestrator))]
public async Task<HttpResponseMessage> StartOrchestrator(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestMessage req,
[DurableClient] IDurableOrchestrationClient starter)
{
var stringContent = await req.Content.ReadAsStringAsync();
var parameter = GetParam(stringContent);
if (string.IsNullOrEmpty(filter.MyParam))
{
//Here I want to prevent start of the orchestration with a 400 bad request error
return req.CreateErrorResponse(HttpStatusCode.BadRequest, "Request doesn't contains MyParam");
}
var instanceId = await starter.StartNewAsync(nameof(RunOrchestrator), parameter);
return starter.CreateCheckStatusResponse(req, instanceId);
}
The result I'm getting :
Is there a way to do what I'm trying to ?
It should be a semaphore issue, two threads are created right here and azure functions doesn't support synchronouse operations so this is where the 500 is coming from.
The solution is to set the variable FUNCTIONS_V2_COMPATIBILITY_MODE
I have a client using HttpClient.GetAsync to call into a Azure Function Http Trigger in .Net 5.
When I call the function using PostMan, I get my custom header data.
However, when I try to access my response object (HttpResponseMessage) that is returned from HttpClient.GetAsync, my header data empty.
I have my Content data and my Status Code. But my custom header data are missing.
Any insight would be appreciated since I have looking at this for hours.
Thanks for you help.
Edit: Here is the code where I am making the http call:
public async Task<HttpResponseMessage> GetQuotesAsync(int? pageNo, int? pageSize, string searchText)
{
var requestUri = $"{RequestUri.Quotes}?pageNo={pageNo}&pageSize={pageSize}&searchText={searchText}";
return await _httpClient.GetAsync(requestUri);
}
Edit 8/8/2021: See my comment below. The issue has something to do with using Blazor Wasm Client.
For anyone having problems after following the tips on this page, go back and check the configuration in the host.json file. you need the Access-Control-Expose-Headers set to * or they won't be send even if you add them. Note: I added the "extensions" node below and removed my logging settings for clarity.
host.json (sample file):
{
"version": "2.0",
"extensions": {
"http": {
"customHeaders": {
"Access-Control-Expose-Headers": "*"
}
}
}
}
This is because HttpResponseMessage's Headers property data type is HttpResponseHeaders but HttpResponseData's Headers property data type is HttpHeadersCollection. Since, they are different, HttpResponseHeaders could not bind to HttpHeadersCollection while calling HttpClient.GetAsync(as it returns HttpResponseMessage).
I could not find a way to read HttpHeadersCollection through HttpClient.
As long as your Azure function code is emitting the header value, you should be able to read that in your client code from the Headers collection of HttpResponseMessage. Nothing in your azure function (which is your remote endpoint you are calling) makes it any different. Remember, your client code has no idea how your remote endpoint is implemented. Today it is azure functions, tomorrow it may be a full blown aspnet core web api or a REST endpoint written in Node.js. Your client code does not care. All it cares is whether the Http response it received has your expected header.
Asumming you have an azure function like this where you are adding a header called total-count to the response.
[Function("quotes")]
public static async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("Quotes");
logger.LogInformation("C# HTTP trigger function processed a request for Quotes.");
var quotes = new List<Quote>
{
new Quote { Text = "Hello", ViewCount = 100},
new Quote { Text = "Azure Functions", ViewCount = 200}
};
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("total-count", quotes.Count.ToString());
await response.WriteAsJsonAsync(quotes);
return response;
}
Your existing client code should work as long as you read the Headers property.
public static async Task<HttpResponseMessage> GetQuotesAsync()
{
var requestUri = "https://shkr-playground.azurewebsites.net/api/quotes";
return await _httpClient.GetAsync(requestUri);
}
Now your GetQuotesAsync method can be called somewhere else where you will use the return value of it (HttpResponseMessage instance) and read the headers. In the below example, I am reading that value and adding to a string variable. HttpResponseMessage implements IDisposable. So I am using a using construct to implicitly call the Dispose method.
var msg = "Total count from response headers:";
using (var httpResponseMsg = await GetQuotesAsync())
{
if (httpResponseMsg.Headers.TryGetValues("total-count", out var values))
{
msg += values.FirstOrDefault();
}
}
// TODO: use "msg" variable as needed.
The types which Azure function uses for dealing with response headers is more of an implementation concern of azure functions. It has no impact on your client code where you are using HttpClient and HttpResponseMessage. Your client code is simply dealing with standard http call response (response headers and body)
The issue is not with Blazor WASM, rather if that header has been exposed on your API Side. In your azure function, add the following -
Note: Postman will still show the headers even if you don't expose the headers like below. That's because, Postman doesn't care about CORS headers. CORS is just a browser concept and not a strong security mechanism. It allows you to restrict which other web apps may use your backend resources and that's all.
First create a Startup File to inject the HttpContextAccessor
Package Required: Microsoft.Azure.Functions.Extensions
[assembly: FunctionsStartup(typeof(FuncAppName.Startup))]
namespace FuncAppName
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<HttpContextAccessor>();
}
}
}
Next, inject it into your main Function -
using Microsoft.AspNetCore.Http;
namespace FuncAppName
{
public class SomeFunction
{
private readonly HttpContext _httpContext;
public SomeFunction(HttpContextAccessor contextAccessor)
{
_httpContext = contextAccessor.HttpContext;
}
[FunctionName("SomeFunc")]
public override Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, new[] { "post" }, Route = "run")] HttpRequest req)
{
var response = "Some Response"
_httpContext.Response.Headers.Add("my-custom-header", "some-custom-value");
_httpContext.Response.Headers.Add("my-other-header", "some-other-value");
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "my-custom-header, my-other-header");
return new OkObjectResult(response)
}
If you want to allow all headers you can use wildcard (I think, not tested) -
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "*");
You still need to add your web-app url to the azure platform CORS. You can add * wildcard, more info here - https://iotespresso.com/allowing-all-cross-origin-requests-azure-functions/
to enable CORS for Local Apps during development - https://stackoverflow.com/a/60109518/9276081
Now to access those headers in your Blazor WASM, as an e.g. you can -
protected override async Task OnInitializedAsync()
{
var content = JsonContent.Create(new { query = "" });
using (var client = new HttpClient())
{
var result = await client.PostAsync("https://func-app-name.azurewebsites.net/api/run", content);
var headers = result.Headers.ToList();
}
}
I have office 365 trigger "when new e-mail arrives?"
i initialize a variable username with value Max Sample
Then called azure function FxNet21HttpTrigger1
and if determine there a username for the Logic App is this possible to chnge it there give another Variable back
check the the username and do one thing if it is "Donald Duck" or another thing if not
I'm searching for a minimal way to set value in the azure function and react on the value in the logic app.
Logic App Designer Screenshot
This is using Version 1 Azure functions (version 2 and 3 are similar):
using System.Net;
using System.Net.Http;
....
[FunctionName("MyFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
return new GetHtmlResponseContent("<html><body>Hello <b>world</b></body></html>"};
}
private static HttpResponseMessage GetHtmlResponseContent(string msg, HttpStatusCode httpStatusCode)
{
var response = new HttpResponseMessage(httpStatusCode);
response.Content = new StringContent(msg));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response;
}
You might want to return a JSON payload containing your return value(s).
How do I return JSON from an Azure Function
In Azure portal, one can easily configure the output bindings of an Azure function, from the 'Integrate' page of that function.
These settings Eventually go into the function.json.
My question is, how can I set these values from Visual studio ?
The code looks like this:
public static class SomeEventProcessor
{
[FunctionName("SomeEventProcessor")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
TraceWriter log,
IAsyncCollector<EventInfo> outputQueue)
{
log.Info("C# HTTP trigger function processed a request.");
EventInfo eventInfo = new EventInfo(); //Just a container
eventInfo.SomeID = req.Headers.Contains("SomeID") ? req.Headers.GetValues("SomeID").First() : null;
//Write to a queue and promptly return
await outputQueue.AddAsync(eventInfo);
return req.CreateResponse(HttpStatusCode.OK);
}
}
I want to specify which queue and which storage to use, from VS, so that I can source control my code and config. I have checked out similar questions, suggested questions etc, but none proved handy.
I am using
Visual studio 2017 preview, Version 15.3.0 Preview 3
VS Extension: Azure Function tools for VS, version 0.2
The bindings are specified just as your trigger, using attributes on the parameters they should be bound to. The binding configuration (e.g. the queue name, connection, etc.) is provided as attribute parameters/properties.
Using your code as an example, a queue output binding would look like this:
public static class SomeEventProcessor
{
[FunctionName("SomeEventProcessor")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")]HttpRequestMessage req,
TraceWriter log,
[Queue("myQueueName", Connection = "myconnection")] IAsyncCollector<EventInfo> outputQueue)
{
log.Info("C# HTTP trigger function processed a request.");
EventInfo eventInfo = new EventInfo(); //Just a container
eventInfo.SomeID = req.Headers.Contains("SomeID") ? req.Headers.GetValues("SomeID").First() : null;
//Write to a queue and promptly return
await outputQueue.AddAsync(eventInfo);
return req.CreateResponse(HttpStatusCode.OK);
}
}
If you're just returning a 200 from your HTTP function (Ok), you can furtner simplify your code by applying the attribute to the method's return value, which, again using your code as an example, would look like this:
[FunctionName("SomeEventProcessor")]
[return: Queue("myQueueName", Connection = "myconnection")]
public static EventInfo Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")]HttpRequestMessage req,
TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
EventInfo eventInfo = new EventInfo(); //Just a container
eventInfo.SomeID = req.Headers.Contains("SomeID") ? req.Headers.GetValues("SomeID").First() : null;
return eventInfo;
}
Using the code above, Azure Functions will automatically return a 200 when your functions succeeds and a 500 when/if an exception is thrown.
I have a device that sends data in text form to a blob on AZURE, once the blob receives the data it triggers a function in azure functions which is basically and executable file made from c++ code, when it finishes it generates another text file which is stored in other blob
it is a very simple operation. But now I would like to receive an email each time the function goes trough successfully, I have searched on the web but the tutorial are very confusing or does not address this simple task.
I did developed the executable file with c++ but I inherited the azure function from someone else and I have zero experience with azure (i am electrical engineer not computer science). The azure function is written in C#, I just need a guide.
Thank you in advance!!
Use can add SendGrid output binding to you C# Azure Function. The binding in function.json would look something like this:
{
"name": "mail",
"type": "sendGrid",
"direction": "out",
"apiKey" : "MySendGridKey"
}
and function body like this:
#r "SendGrid"
using SendGrid.Helpers.Mail;
public static void Run(string input, out string yourExistingOutput, out Mail message)
{
// Do the work you already do
message = new Mail
{
Subject = "Your Subject"
};
var personalization = new Personalization();
personalization.AddTo(new Email("recipient#contoso.com"));
Content content = new Content
{
Type = "text/plain",
Value = "Email Body"
};
message.AddContent(content);
message.AddPersonalization(personalization);
}
Read about SendGrid and SendGrid bindings.
I had a similar problem which Mikhail's solution helped me solve. In my case I wanted the static Run method to be asynchronously, which meant I couldn't use the out parameter modifier. My solution's slightly different as it is a timer trigger and was implemented using Visual Studio and the NuGet package Microsoft.Azure.Webjobs.Extensions.SendGrid v2.1.0.
[FunctionName("MyFunction")]
public static async Task Run(
[TimerTrigger("%TimerInterval%")]TimerInfo myTimer,
[SendGrid] IAsyncCollector<Mail> messages,
TraceWriter log)
{
log.Info($"C# Timer trigger function started execution at: {DateTime.Now}");
// Do the work you already do...
log.Info($"C# Timer trigger function finished execution at: {DateTime.Now}");
var message = new Mail();
message.From = new Email("from#email.com");
var personalization = new Personalization();
personalization.AddTo(new Email("to#email.com"));
personalization.Subject = "Azure Function Executed Succesfully";
message.AddPersonalization(personalization);
var content = new Content
{
Type = "text/plain",
Value = $"Function ran at {DateTime.Now}",
};
message.AddContent(content);
await messages.AddAsync(message);
}
This solution used Zain Rivzi's answer to How can I bind output values to my async Azure Function?
and the SendGrid Web API v3 quick start guide.
The answer can be slightly simplified:
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using SendGrid.Helpers.Mail;
public static class ExtractArchiveBlob
{
[FunctionName("MyFunction")]
public static async Task RunAsync(string input,
[SendGrid(ApiKey = "SendGridApiKey")]
IAsyncCollector<SendGridMessage> messageCollector)
{
var message = new SendGridMessage();
message.AddContent("text/plain", "Example content");
message.SetSubject("Example subject");
message.SetFrom("from#email.com");
message.AddTo("to#email.com");
await messageCollector.AddAsync(message);
}
}
Where SendGridApiKey is the app setting holding your Send Grid api key.