Adding middleware or alike in Azure functions v2 - c#

I need to add correlationId to my logging context and I did it on my MVC project by adding CorrelationId nuget to the project and setting up its middleware, but I could not do the same in Azure functions.
I have loaded the ICorrelationContextAccessor using Dependency injection and then set my correlationId like this:
[FunctionName("func1")]
public async Task Run([ServiceBusTrigger("mytopic", "MySubscription", Connection = "ServiceBusConnectionString")]Message message)
{
_correlationContextAccessor.CorrelationContext = _correlationContextFactory.Create(message.CorrelationId, "X-Correlation-ID");
_logger.LogInformation($"C# ServiceBus topic trigger function processed message: {message.MessageId}, {Encoding.UTF8.GetString(message.Body)}");
It works fine and I see my correlationId in the log line below and in my services in the function. The only part that I am missing is that I have logs regarding the start and finish of the function that still has no correlationId, which kind of make sense becaue when the function wants to log that it has received the message the correlationId is not set.

The short version is that you can't effect the logging code that runs before your function using the built in bindings.
You won't be able to change that first "C# Timer trigger function processed message" as the message hasn't been read at that point-- it would be the same as trying to get the correlation ID set in your MVC project before reading the incoming HTTP request.
You could add logging as soon as the message is first received by creating a custom binding. I would encourage you to consider carefully whether or not it is worth building and maintaining a custom binding to get your logging setup a few lines sooner.

Related

How to get the value of properties from Serilog Enrichers inside a controller method

I have an ASP.NET Web API project that uses Serilog with the Correlation Id enricher. It works fine for HTTP requests, but I have a few controller endpoints that queue a job for a dedicated async worker to handle when it's free (using Microsoft.Extensions.Hosting.IHostedService). The issue is since these jobs get picked up outside of the initial HTTP request block, they lose the Correlation Id. I know I can push a property to the Logger Context using:
Serilog.Context.LogContext.PushProperty("CorrelationId", request.CorrelationId);
But I'm unsure how to get the existing correlation id that's used in the initial HTTP request. If I do, I can send it in the job metadata to be used with the async jobs later. Any ideas?

Does the Azure service bus client automatically use a retries for transient errors returned from the service bus?

I have a very simple Azure function that uses an Http Trigger to send messages to an Azure Service Bus topic. I want to retry this function if the service bus returns a transient error. I have reviewed the default policy, but I don't know how to verify if it will be used out of the box. Do I need to add anything to my function code to ensure that such a retry policy will be used?
I also want to log messages that fail to be loaded onto the service bus after the retry policy fails. Should I wrap the contents of the function in a try-catch block and perform the log in the catch statement?
[FunctionName("MessageLoader")]
[return: ServiceBus("%Topic_Name%", Connection = "Topic_Connection")]
public static async Task<TopicMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "domain/load-message")] HttpRequestMessage req)
{
var stringRequestBody = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TopicMessage>(stringRequestBody);
}
Yes, in this case (Service Bus binding), the default retry policy is used. You do not need to do anything special. To verify if it's working, you should see failed dependencies in app insights whenever a call fails if you integrated it correctly.
To your second question, if it fails after the retry gives up, you do not need to log manually. You should see error logged in app insights automatically captured if you integrated it correctly.
If you want to log custom error on failure, you should use Servicebus message sender by creating it yourself instead of Function output binding.

How can I listen for the end of a build using VSTS WebApi?

I'm building as part of a larger process that analyzes the results of the build once it has completed. I used to work with XAML builds via C# code, and I had the following code:
QueuedBuild.Connect();
QueuedBuild.PollingCompleted += PrivateServerBuildRequest.BuildCompleted;
(QueuedBuild was IQueuedBuild type),
With new WebApi builds, do I have an event that let me know that the build has completed?
I found BuildCompletedEvent in Microsoft.TeamFoundation.Build.WebApi.Events but I didn't manage to find the way to use it.
Is there any equivalent to PollingCompleted event in WebApi builds? Something that'll fire once all build results are available?
One of the possible alternatives with the new REST API is to use Service Hooks. In particular, you might want to pay attention to the generic Web Hook, whcih can basically instruct VSTS to POST some JSON payload (once a certain event occurs) to some endpoint.
The endpoint can be anything: your custom home-made service hosted on-prem, OR an Azure Function, for instance. This article can give you an idea how to trigger an Azure Function in response to a VSTS event.
The 'Build Completed' event is in the list of available events.
So, to sum it all up, I would try the following in your case:
Create an Azure Function to accept the build info payload and process it accordingly
Subscribe to Build Completed event with the Web Hook and make sure the Azure Function URL is used as the endpoint

CanĀ“t add header to MassTransit message from OperationContext?

I am trying to add a header to a Masstransit message containing information from the currently logged user on a WCF Web application.
So at my web app, I have the following when the app starts:
IBusControl bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host(new Uri("rabbitmq://localhost/test"), r =>
{
//...
});
cfg.ConfigureSend(
s => s.UseSendExecute(
c => c.Headers.Set(Constants.UserInfo,
OperationContext.Current.Channel.Extensions.Find<PropertyUserInfo>().Info)));
});
I am using an IoC container to create IBusControl only once in the application (singleton scope), then IBusControl gets injected into the Web service.
Note that OperationContext.Current does not exists when I am creating the servicebus, I am expecting the lambda c= > c.Headers.Set(...) to be called within the request context
Now, when the user makes a request, I am using a request-response pattern (although I dont think this matters)
var requestClient = _bus.CreateRequestClient<AddTicketRequest, AddTicketResponse>(uri, timeout);
var response = requestClient.Request(requestMessage);
The problem is, when this code is executed, and Masstransit tries to add the header to the message, OperationContext.Current is null as apparently it is running on a different thread then the user call.
Oddly enough, eventually Masstransit starts to call UseSendExecute from the right thread, and everything starts to work. And I have to restart IIS to replicate the bug again (!?).
Has anybody ever had this problem ? thanks.
I know I can add the Header when publishing the message, but I wanted to have all messages originated from the web application to have this header, and was expecting have it set up globally.
The issue https://github.com/MassTransit/MassTransit/issues/921 looks related. I'll go with the same workaround, and I will work with a wrapper around IBusControl.

Is there a way to make Azure WebJobs ServiceBus out parameter optional?

I am building a console application that will be run as a continuous Azure WebJob. I am using the Azure WebJobs SDK via the Nuget Package Microsoft.Azure.Jobs.ServiceBus v0.3.1-beta (prerelease). I have static method that triggers on an Azure ServiceBus queue. I do some processing and then want to have the option to send a response via the output parameter to another queue. The method signature looks like this:
public static void TriggerOnQueue(
[ServiceBusTrigger(QueueName)] BrokeredMessage receivedMessage,
[ServiceBus(QueueResponseName)] out BrokeredMessage responseMessage)
{
...
}
My initial thought was to set the responseMessage to null. However, when I do this an error appears in the console window. It doesn't stop execution (so it technically does what I want it to do), but I would rather not push something throwing errors to production. Is there any non-hackish way to set a value in the response message that will not throw an error, but will not submit the message to the response queue?
If not, is there another pattern I am missing that I could use? I would prefer to use the pipeline feature of the WebJobs SDK as opposed to creating the output queue manually. I could probably submit the requests that need a response on to a separate queue and have 2 separate triggers, but with the small amount I am having this do I would rather keep it simple and together.
Thoughts?
This pattern of specifying null for an out parameter works for Azure Queues but it throws an exception for Service Bus Queues. This looks like bug in the SDK. I will open a bug for us to fix it. Thank you for reporting this issue

Categories