MediatR command inside Azure Function ServiceBusTrigger - c#

Using some references, I have created the Azure Function App with Clean Architecture and the Project structure looks like this:
My Azure Function is of the type Service Bus Queue Trigger. Basically, I want to Call MediatR command CreateProductCommand inside this function trigger. So that, whenever there is a message pushed into Service bus Queue, I can read that and save that into SQL database using this MediatR command. CreateProductCommand has EF Core implementation.
public class SaveProductDataToDatabase
{
private readonly IMediator _mediator;
public SaveProductDataToDatabase(IMediator mediator)
{
_mediator = mediator;
}
[FunctionName("SaveProductDataToDatabase")]
public void Run([ServiceBusTrigger("product-data-dev-01", Connection = "ServiceBusConnectionString")] string myQueueItem, ILogger log)
{
log.LogInformation($"Processed message: {myQueueItem}");
}
}
I'm not sure how to use the CreateProductCommand inside this function trigger. Please help.

Adding MediatR command handler on top of a function is redundant as function is already a handler in itself and a small unit of work. A function has a single responsibility usually that responsibility is encapsulated in the function code. Unless your function has multiple responsibilities, which it shouldn’t, MediatR is unnecessary.

Related

Does Transient Dependency Injection of an ServiceBus Azure Function will be injected for every run?

I have an Azure Function that listens for a ServiceBus and one of the roles of the process is to generate some GUIDs.
I can't share my code but it look something like this:
public class ServiceBusListenerFunction
{
private readonly IProcessService _processService;
public ServiceBusListenerFunction(IProcessService processService)
{
_processService = processService;
}
[FunctionName("MyServiceBusFunction")]
public async Task Run([ServiceBusTrigger("my-queue")] string message)
{
await _processService.Run(message);
}
}
I injected IProcessService as Transient in an atempt to inject for every Run call of my function.
My concern are all concurrent calls, even for a very little chance, generate duplicate GUID.
There is a way to manually inject IProccessService and all its dependencies for every call?
Thank you in advance!

Azure Function Trigger Name/Connections from App Configuration

Is there now a way to set the Trigger Properties(Name/Connection) using the value from Azure App Configuration?.
I added a startup class that reads the data from Azure App Configuration but it seems the trigger set its properties earlier than that, therefore not able to bind the data that came from the app configuration.
I also found this thread about it but im not sure if there is a new update?:
https://github.com/MicrosoftDocs/azure-docs/issues/63419
https://github.com/Azure/AppConfiguration/issues/203
You can do this. The following code gets the name of the queue to monitor from an app setting, and it gets the queue message creation time in the insertionTime parameter:
public static class BindingExpressionsExample
{
[FunctionName("LogQueueMessage")]
public static void Run(
[QueueTrigger("%queueappsetting%")] string myQueueItem,
DateTimeOffset insertionTime,
ILogger log)
{
log.LogInformation($"Message content: {myQueueItem}");
log.LogInformation($"Created at: {insertionTime}");
}
}
Similarly, you can use this approach for other triggers.

Call method after Logging .Net 5

I have a .Net Worker program that uses multiple NuGet packages that log information to ILogger. For each of the NuGet packages, I am delegating same "master" logger object. For each of the log information, I would like to now fetch and send to our internal chat. I trying to create an Event that will execute a "CallMeWhenLog" method every time a new string is added to ILogger.
public class TestClass
{
private readonly ILogger<TestClass> _logger;
public TestClass(ILogger<TestClass> logger)
{
_logger = logger;
}
public async Task Process(Message message,
CancellationToken cancellationToken = default)
{
_logger.LogInformation("New message!");
_logger.LogError("New message!", ex);
}
public void CallMeWhenLog(string loggedMessage)
{
var chatHandler = new ChatHandler();
chatHandler.SendMessage(loggedMessage);
}
}
I think it is possible by creating a subscription to ILogger but I never used events before. It sounds straight forward but I am a bit lost. For example, I would like to call "CallMeWhenLog" method just after _logger.LogInformation and _logger.LogError is executed.
From your comment it seems like you're using (ASP).NET Core.
You may want to look into creating your own Logger - docs, and registering it just like the other three logging provides (e.g. logging.AddEventLog()). You can implement posting to the chat in that custom logger.
Or take a look at the 3rd party providers: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0#third-party-logging-providers

Azure Service Bus Triggered Function - Bind to MessageReceiver

I'm trying to bind to MessageReceiver in an Azure Service Bus Triggered Function.
My goal is to handle dead letter queue messages and complete them.
public static class Function1
{
[FunctionName("Function1")]
public static async Task Run(
[ServiceBusTrigger(
"<topicName>",
"<subscriptionName>/$DeadLetterQueue",
Connection = "connectionstring")]
Message message,
ILogger logger,
MessageReceiver messageReceiver)
{
// TODO: Perform some actions
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
}
The problem is that it fails to bind to the MessageReceiver class.
Microsoft.Azure.WebJobs.Host: Error indexing method 'Function1'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'receiver' to type MessageReceiver. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
Any ideas why the binding fails?
I figured out what was wrong. I was using 'receiver' as parameter name for MessageReceiver. It turned out that the parameter name has to be 'messageReceiver'. The example I was looking at first used 'receiver', so is this maybe something that has changed?

Instantiate SignalR Hub Object With IHubContext

It seems like a big use for SignalR Hubs is to display the actions of one client to all of the other clients. What I hope to use SignalR for is when a certain event happens in my server side code, I want to instantiate a hub object and invoke one of its methods to communicate with all of the clients. If you see my previous post (Route To Take With SqlDependency OnChange), I would like to do this in the OnChange method of SqlDependency. Upon researching it I have found some people talk about using an IHubContext object, though I haven't found many examples of instantiation and actual sending data to clients.
Is this possible to do (and what might sending data to all clients with IHubContext look like if possible), and if not, are there any ways I might be able to get around instantiating a hub like this?
SignalR for ASP.NET Core
You can create a class that has the IHubContext<T> injected in. Inject other dependencies if you want, or resolve the service from controllers or other classes.
public class NotificationService
{
private readonly IHubContext<MyHub> _myHubContext;
public NotificationService(IHubContext<MyHub> myHubContext)
{
_myHubContext= myHubContext;
}
public async Task SendMessage(string message)
{
await _myHubContext.Clients.All.SendAsync("Update", message);
}
}
Assuming you're using SqlDependency from an IHostedService:
public class MyHostedService : IHostedService
{
public MyHostedService(
NotificationService notificationService)
{
// TODO get reference to sqlDependency
sqlDependency.OnChange += (s, e) => _notificationService.SendMessage(e.Info.ToString());
}
}
SignalR for ASP.NET
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.All.sendMessage(message);
You need to use using Microsoft.AspNet.SignalR library.
using Microsoft.AspNet.SignalR;
//Instantiating. SignalRHub is the hub name.
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
//sends message
context.Clients.Client(ClientId).sendMessage(data);

Categories