如何将ServiceBusClient注册到依赖注入中?

22

我正在尝试注册新的Azure.Messaging.ServiceBus包中推荐使用的ServiceBusClientBuilderExtensions来进行依赖注入,具体方法如同这篇文章所述,但我无法找到任何关于如何操作的文档或在线帮助。

我想添加如下内容:

public override void Configure(IFunctionsHostBuilder builder)
{
    ServiceBusClientBuilderExtensions.AddServiceBusClient(builder, Typsy.Domain.Configuration.Settings.Instance().Connections.ServiceBusPrimary);
}

但是我遇到了错误

类型 'Microsoft.Azure.Functions.Extensions.DependencyInjection.IFunctionsHostBuilder' 必须转换为 'Azure.Core.Extensions.IAzureClientFactoryBuilder',才能在泛型方法 'IAzureClientBuilder<ServiceBusClient,ServiceBusClientOptions> Microsoft.Extensions.Azure.ServiceBusClientBuilderExtensions.AddServiceBusClient(this TBuilder, string)' 的参数'TBuilder'中使用它

输入图像描述

如果有人可以帮忙解决这个问题,那就太好了!

4个回答

41

ServiceBusClientBuilderExtensions.AddServiceBusClientIAzureClientFactoryBuilder的扩展方法:

public static IAzureClientBuilder<ServiceBusClient, ServiceBusClientOptions> AddServiceBusClient<TBuilder>(this TBuilder builder, string connectionString)
            where TBuilder : IAzureClientFactoryBuilder
要获取IAzureClientFactoryBuilder实例,您需要针对给定的IServiceCollection调用AzureClientServiceCollectionExtensions.AddAzureClients(IServiceCollection,Action<AzureClientFactoryBuilder>),该方法提供一个委托,返回IAzureClientFactoryBuilder实例。(此方法在Microsoft.Extensions.Azure NuGet包中)
要调用该方法,可以使用IFunctionsHostBuilder提供的IServiceCollection。 完整样例大概如下:
public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddAzureClients(clientsBuilder =>
    {
        clientsBuilder.AddServiceBusClient(Typsy.Domain.Configuration.Settings.Instance().Connections.ServiceBusPrimary)
          // (Optional) Provide name for instance to retrieve by with DI
          .WithName("Client1Name")
          // (Optional) Override ServiceBusClientOptions (e.g. change retry settings)
          .ConfigureOptions(options =>
          {
              options.RetryOptions.Delay = TimeSpan.FromMilliseconds(50);
              options.RetryOptions.MaxDelay = TimeSpan.FromSeconds(5);
              options.RetryOptions.MaxRetries = 3;
          });
    });
}
为检索命名实例,您需要使用IAzureClientFactory< ServiceBusClient >作为注入类型,而不是使用ServiceBusClient。无论您是否使用命名实例,ServiceBusClient都是单例模式。
 public Constructor(IAzureClientFactory<ServiceBusClient> serviceBusClientFactory)
 {
     // Wherever you need the ServiceBusClient
     ServiceBusClient singletonClient1 = serviceBusClientFactory.CreateClient("Client1Name")
 }

这在多个命名空间或连接字符串的情况下如何工作? - user1142433
1
@devNull,你知道在将ServiceBusClient注册为依赖项时,它是否被注册为Singleton吗?如果没有,你有任何想法如何将其注册为Singleton吗? - Shanuka Gomes
你知道我如何在注册ServiceBusClient作为依赖项时传递ServiceBusClientOptions吗? - Shanuka Gomes
要从ConfigureService方法中访问设置,您可以使用var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:ServiceConnectionStrings"); - 请参阅有关环境变量的Microsoft文章:https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library?tabs=v2%2Ccmd#environment-variables - codea
@codea 使用上下文也是一种选择 https://learn.microsoft.com/zh-cn/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources - KwaXi
显示剩余4条评论

11

对于只需要单个服务总线客户端的用户,一个简单的单例就足够了。

(在 .Net 6 Azure Functions v4 中进行了测试):

using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System;

[assembly: FunctionsStartup(typeof(YourProjName.Startup))]

namespace YourProjName
{
 public class Startup : FunctionsStartup
 {
    public override void Configure(IFunctionsHostBuilder builder)
    {
       
        var serviceBusConnectionString = Environment.GetEnvironmentVariable("ServiceBusConnectionString");
        if (string.IsNullOrEmpty(serviceBusConnectionString))
        {
            throw new InvalidOperationException(
                "Please specify a valid ServiceBusConnectionString in the Azure Functions Settings or your local.settings.json file.");
        }

        //using AMQP as transport
        builder.Services.AddSingleton((s) => {
            return new ServiceBusClient(serviceBusConnectionString, new ServiceBusClientOptions() { TransportType = ServiceBusTransportType.AmqpWebSockets }); 
        });

    }
 }
}

然后您可以在Azure函数构造函数中使用它:

public Function1(ServiceBusClient client)
   {
       _client = client;
   }

这不好,因为ServiceBusClient实例没有正确释放。 - undefined

5
虽然回答晚了,但这篇文章提供了一些很好的例子,包括发送者和客户端的DI设置。

https://learn.microsoft.com/en-us/dotnet/api/overview/azure/messaging.servicebus-readme?view=azure-dotnet#registering-with-aspnet-core-dependency-injection

public async Task ConfigureServicesAsync(IServiceCollection services)
{
var adminClient = new ServiceBusAdministrationClient("<< SERVICE BUS CONNECTION STRING >>");
var queueNames = new List<string>();

await foreach (var queue in adminClient.GetQueuesAsync())
{
    queueNames.Add(queue.Name);
}

services.AddAzureClients(builder =>
{
    builder.AddServiceBusClient("<< SERVICE BUS CONNECTION STRING >>");

    foreach (var queueName in queueNames)
    {
        builder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
            provider
                .GetService<ServiceBusClient>()
                .CreateSender(queueName)
        )
        .WithName(queueName);
    }
});

}

以这种方式进行操作的问题在于队列和主题应该从一开始就存在,否则您必须重新启动服务来加载它们。 - undefined

3
我也曾经想过同样的问题,虽然有一个专门的Azure扩展,但我找到了另一种方法,更简单易懂,希望能帮助其他人。
代码使用了`AddSingleton`方法提供的函数委托。这个函数委托会在构建结束时被调用,在这里你可以利用服务提供程序并检索你的选项(如果我理解有误,请纠正我,因为文档既密集又稀疏 :))。
以下是关键部分:
serviceCollection.AddSingleton((serviceProvider) =>
{
    ServiceBusOptions options = serviceProvider.GetService<IOptions<ServiceBusOptions>>().Value;
    return new ServiceBusClient(options.ConnectionString);
});

**完整的代码 - 更加详细 :) **

using Azure.Messaging.ServiceBus;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

namespace ConsoleJson.Example
{
    class Startup
    {
        private static IHost DIHost;

        static void Main(string[] args)
        {
            IHostBuilder hostbuilder = Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration(GetAppConfigurationDefinition);

            //Create Host (/build configuration)
            ConfigureSettings(hostbuilder);
            ConfigureServices(hostbuilder);

            DIHost = hostbuilder.Build();

            // Application code should start here.
            DIHost.Run();
        }


        static void GetAppConfigurationDefinition(HostBuilderContext ctx, IConfigurationBuilder config)
        {
            config.SetBasePath(Environment.CurrentDirectory)
           .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) // for simplicity appsettings.production.json / appsettings.development.json are not there.  This is where settings would go.
           .Build();
        }

        public static void ConfigureServices(IHostBuilder hostbuilder)
        {
            hostbuilder.ConfigureServices((hostContext, serviceCollection) =>
            {

                serviceCollection.AddSingleton<ServiceBusClient>((serviceProvider) =>
                {
                    // options from appSettings.json
                    // leverages IOptions Pattern to get an options object from the DIHost Service provider
                    var myServiceBusOptions = serviceProvider.GetService<IOptions<ServiceBusOptions>>().Value;

                    var sbClientOptions=new ServiceBusClientOptions() { 
                        TransportType=ServiceBusTransportType.AmqpTcp,
                        RetryOptions=new ServiceBusRetryOptions() { Mode = ServiceBusRetryMode.Exponential }
                        // ...
                    };

                    // returns the ServiceBusClient Object configured per options we wanted
                    return new ServiceBusClient(myServiceBusOptions.ConnectionString, sbClientOptions);
                });

            });
        }

        public static void ConfigureSettings(IHostBuilder hostbuilder)
        {
            hostbuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
            {
                IConfiguration configurationRoot = hostBuilderContext.Configuration;
                serviceCollection.Configure<ServiceBusOptions>(configurationRoot.GetSection("ServiceBusOptions"));
            });
        }

        public class ServiceBusOptions
        {
            public string ConnectionString { get; set; }
        }

    }
}

AppSettings.Json

{
    "ServiceBusOptions": {
        "ConnectionString": ""
    }
}

4
以这种方式实例化ServiceBusClient意味着处理方式不会由服务容器处理。https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#services-not-created-by-the-service-container - NeedHack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接