简体   繁体   English

在ASP.net Core中注入多个ServiceBusClient

[英]Inject multiple ServiceBusClient in ASP.net Core

I want to inject multiple ServiceBusClient with same connectionstring but different queue name.我想注入多个具有相同连接字符串但队列名称不同的 ServiceBusClient。

    _services.TryAddSingleton(implementationFactory =>
    {
        var serviceBusConfiguration = implementationFactory.GetRequiredService<Microsoft.Extensions.Options.IOptions<UserEventConsumerSetting>>().Value;
    
        var serviceBusClient = new ServiceBusClient(serviceBusConfiguration.ServiceBusConnectionString, new ServiceBusClientOptions
        {
            TransportType = ServiceBusTransportType.AmqpWebSockets
        });
    
        return serviceBusClient.CreateReceiver(serviceBusConfiguration.ServiceBusQueueName, new ServiceBusReceiverOptions
        {
            ReceiveMode = ServiceBusReceiveMode.PeekLock
        });
    });

In order to use I have to create ServiceBusSender Instance.为了使用我必须创建 ServiceBusSender 实例。

    private readonly ServiceBusSender _serviceBusSender;
    
    public CarReservationMessagingService(ServiceBusSender serviceBusSender)
    {
        _serviceBusSender = serviceBusSender ?? throw new ArgumentNullException(nameof(serviceBusSender));
    }
    
    public async Task PublishNewCarReservationMessageAsync(CarReservation carReservation)
    {
        var carReservationIntegrationMessage = new CarReservationIntegrationMessage
        {
            Id = Guid.NewGuid().ToString(),
            CarId = carReservation.CarId,
            CustomerId = carReservation.CustomerId,
            RentFrom = carReservation.RentFrom,
            RentTo = carReservation.RentTo
        };
    
        var serializedMessage = JsonSerializer.Serialize(carReservationIntegrationMessage);
        ServiceBusMessage message = new ServiceBusMessage(serializedMessage);
        await _serviceBusSender.SendMessageAsync(message);
    }

How can I inject multiple servicebusclient and use them differently?如何注入多个 servicebusclient 并以不同方式使用它们?

For anyone coming here in the future, I'd recommend using ServiceBusClientBuilderExtensions对于将来来到这里的任何人,我建议使用ServiceBusClientBuilderExtensions

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddAzureClients(clientsBuilder =>
    {
        clientsBuilder.AddServiceBusClient("Client1ConnectionString")
          .WithName("Client1Name");
        clientsBuilder.AddServiceBusClient("Client2ConnectionString")
          .WithName("Client2Name");
    });
}

In order to retrieve it you must use IAzureClientFactory<ServiceBusClient> as below:为了检索它,您必须使用IAzureClientFactory<ServiceBusClient>如下:

 public Constructor(IAzureClientFactory<ServiceBusClient> serviceBusClientFactory)
 {
     ServiceBusClient client1 = serviceBusClientFactory.CreateClient("Client1Name")
 }

Code snippets taken and simplified from this answer.这个答案中提取和简化的代码片段。

So, In other IoC containers (like Unity) there is posibility to specify named dependencies.因此,在其他 IoC 容器(如 Unity)中,可以指定命名依赖项。 You specify name when regster something like this:您在注册时指定名称,如下所示:

container.RegisterSingleto<SomeClassImplementation>("Name")

and then in class where you use is it you should specify attribute with this name然后在您使用的 class 中,您应该使用此名称指定属性

[DependencyAttribute("Name")]

But there are no such function in .net core.但是.net内核中没有这样的function。 You can use Unity.您可以使用统一。 Or you can make some imitation of this functionality.或者你可以对这个功能进行一些模仿。

Let's create enum (or constants if you want)让我们创建枚举(如果需要,也可以创建常量)

enum ServiceBusQueue { ServiceBus1, ServiceBus2, ServiceBus3}

Then create service buc provider然后创建服务 buc 提供者

public class ServiceBusQueueProvider
{
    private Dictionary<ServiceBusQueue, ServiceBusSender > _senders;

    public ServiceBusQueueProvider()
    {
        //Method to initialize all queues with all names and store it in _senders;
    }

    public ServiceBusSender Resolve(ServiceBusQueue queue)
    {
        return _senders[queue];
    }
}

Then register this provider and use it in other clusses that you need to get different quees:然后注册这个提供者并在你需要获得不同队列的其他类中使用它:

 _services.TryAddSingleton(implementationFactory => ServiceBusQueueProvider());

and in constructor:在构造函数中:

public SomeClass(ServiceBusQueueProvider provider)
{
    _serviceBusSender  = provider.Resolve(ServiceBusQueue.ServiceBus1);
}

One more point is that you should change MessagingServiceConfiguration This class is mapped to configuration.还有一点是你应该改变 MessagingServiceConfiguration 这个 class 映射到配置。 And in current implementation you can specify only one queue.在当前的实现中,您只能指定一个队列。 Change it like:像这样改变它:

public class MessagingServiceConfiguration
{
    public List<MessagingServiceConfigurationItem> Queues { get; set; }
}

public class MessagingServiceConfigurationItem
{
    public string QueueName { get; set; }
    public string ListenAndSendConnectionString { get; set; }
}

You can create a class as below with interface.您可以使用接口创建如下 class。 Here is a very basic example.这是一个非常基本的例子。

Interface:界面:

 public interface IAzureServiceBusConsumer
{
    Task Start();
    Task Stop();
}

Implimentation:实施:

public class AzureServiceBusConsumer : IAzureServiceBusConsumer
{
    //Service Bus processor 
    private ServiceBusProcessor _userAddedProcessor;        
    private ServiceBusProcessor _userUpdatedProcessor;

    private readonly IUserReceivedService _userReceived;
    private readonly IConfiguration _configuration;       


    private readonly string _serviceBusConnectionString;
    private readonly string _subscriptionUserAdded;
    private readonly string _subscriptionUserUpdated;
    private readonly string _UserAddedMessageTopic;
    

    public AzureServiceBusConsumer(IUserReceivedService userReceived ,IConfiguration configuration)
    {
        _userReceived = userReceived;
        _configuration = configuration;          

        _serviceBusConnectionString = _configuration.GetValue<string>("ServiceBusConnectionString");
        _UserAddedMessageTopic = _configuration.GetValue<string>("UserAddedMessageTopic");
        _subscriptionUserAdded = _configuration.GetValue<string>("UserAddedSubscription");                 
       

        //Create a client to receive messages
        var client = new ServiceBusClient(_serviceBusConnectionString);

        //on client call you can provide different subscription
        _userAddedProcessor = client.CreateProcessor(_UserAddedMessageTopic, _subscriptionUserAdded);
        _userUpdatedProcessor = client.CreateProcessor(_UserAddedMessageTopic, _subscriptionUserUpdated);
    }

    /// <summary>
    /// start the bus processor to look for any messages.
    /// </summary>
    /// <returns></returns>
    public async Task Start()
    {           

        _userAddedProcessor.ProcessMessageAsync += OnUserAddedMessageReceived;
        _userAddedProcessor.ProcessErrorAsync += ErrorHandler;
        await _userAddedProcessor.StartProcessingAsync();
        _userUpdatedProcessor.ProcessMessageAsync += OnUserUpdatedMessageReceived;
        _userUpdatedProcessor.ProcessErrorAsync += ErrorHandler;
        await _userUpdatedProcessor.StartProcessingAsync();
       
    }

    /// <summary>
    /// stop the bus processor and dispose conn.
    /// </summary>
    /// <returns></returns>
    public async Task Stop()
    {
        await _userAddedProcessor.StopProcessingAsync();
        await _userAddedProcessor.DisposeAsync();
        
    }
    Task ErrorHandler(ProcessErrorEventArgs args)
    {
        Console.WriteLine(args.Exception.ToString());
        return Task.CompletedTask;
    }

    private async Task OnUserAddedMessageReceived(ProcessMessageEventArgs args)
    {
        var message = args.Message;
        var body = Encoding.UTF8.GetString(message.Body);

        UserDto _UserRecivedDto = JsonConvert.DeserializeObject<UserDto>(body);

        //Save the recieved message then call CompleteMessageAsync
        await args.CompleteMessageAsync(args.Message);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM