You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 9 Azure Functions V4独立模式下NServiceBus迁移配置问题求助

.NET 9 + Azure Functions v4独立模式下NServiceBus Azure Service Bus迁移问题解决

问题背景

将基于.NET 6的Azure Functions v3项目迁移至.NET 9和Azure Functions v4独立工作者模式时,NServiceBus与Azure Service Bus的集成配置出现兼容性问题,原Transport相关配置无法直接适配新版本API。

原配置代码

NServiceBus配置方法

public static IHostBuilder ConfigureNServiceBus(this IHostBuilder hostBuilder)
{
    // Makes sure JObject is included in the NServiceBus scan
    JObject _ = new();

    var auditQueue = EnvironmentVariableHelper.GetConfigValue(IoC.Configuration, "AuditQueue", "audit");
    var errorQueue = EnvironmentVariableHelper.GetConfigValue(IoC.Configuration, "ErrorQueue", "error");
    var azureTableStorageConnectionString = EnvironmentVariableHelper.GetStringConfigValue("BlobStorageConnection");
    var endpointName = EnvironmentVariableHelper.GetStringConfigValue("ENDPOINT_NAME");
    var tableStorageName = endpointName.Replace("-", string.Empty).Replace(".", string.Empty);

    hostBuilder.UseNServiceBus(configuration =>
    {
        var endpointConfiguration = configuration.AdvancedConfiguration;                        
        endpointConfiguration.AuditProcessedMessagesTo(auditQueue);
        endpointConfiguration.SendFailedMessagesTo(errorQueue);
        endpointConfiguration.UseSerialization<NewtonsoftJsonSerializer>();

        var transport = configuration.Transport;
        transport.TopicName = $"{endpointName}.events";            
        transport.SubscriptionRuleNamingConvention = eventType => eventType.Name.Replace("App.Contracts", string.Empty);

        var conventions = endpointConfiguration.Conventions();
        conventions.DefiningCommandsAs(type => type.Namespace != null && type.Namespace.StartsWith("App.Contracts.Commands"));
        conventions.DefiningEventsAs(type => type.Namespace != null && type.Namespace.StartsWith("App.Contracts.Events"));
                    
        var persistence = endpointConfiguration.UsePersistence<AzureTablePersistence>();
        var tableServiceClient = new TableServiceClient(azureTableStorageConnectionString);
        persistence.UseTableServiceClient(tableServiceClient);
        persistence.DefaultTable(tableStorageName);
                    
        endpointConfiguration.AuditSagaStateChanges(serviceControlQueue: auditQueue);
                    
        ExcludeAssmbliesFromScan(endpointConfiguration);
                    
        endpointConfiguration.EnableInstallers();

        #if DEBUG
                   
        transport.MaxAutoLockRenewalDuration = TimeSpan.FromMinutes(30);
        #endif
    });

    return hostBuilder;
}

项目依赖配置

<ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.0.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.0.1" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.23.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="2.0.0" />

    <PackageReference Include="Google.Apis.Auth.AspNetCore3" Version="1.69.0" />
    <PackageReference Include="Mapster" Version="7.4.0" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.3" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="1.5.1" />
    <PackageReference Include="Microsoft.Graph" Version="5.74.0" />
    
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.*" />
    <PackageReference Include="Microsoft.SqlServer.TransactSql.ScriptDom" Version="170.28.0" />
    <PackageReference Include="NServiceBus.Newtonsoft.Json" Version="4.1.0" />
    <PackageReference Include="NServiceBus.Extensions.Hosting" Version="2.0.0" />    
    <PackageReference Include="NServiceBus.AzureFunctions.Worker.ServiceBus" Version="6.0.0" />
    <PackageReference Include="NSwag.Generation.AspNetCore" Version="14.2.0" />
    <PackageReference Include="TinyMapper" Version="3.0.3" />
</ItemGroup>

错误尝试与报错信息

尝试直接实例化AzureServiceBusTransport进行配置:

var transport = new AzureServiceBusTransport(azureTableStorageConnectionString, TopicTopology.Default);
transport.TopicName($"{endpointName}.events");
transport.SubscriptionRuleNamingConvention = eventType => eventType.Name.Replace("App.Contracts", string.Empty);
endpointConfiguration.UseTransport(transport);

出现以下报错:

'AzureServiceBusTransport' does not contain a definition for 'TopicName' and the best extension method overload 'AzureServiceBusTransportSettingsExtensions.TopicName(TransportExtensions, string)' requires a receiver of type 'NServiceBus.TransportExtensions<NServiceBus.AzureServiceBusTransport>'

'AzureServiceBusTransport.SubscriptionRuleNamingConvention' is obsolete: 'Setting the subscription rule name is accessible via the migration topology. Use MigrationTopology.EventToMigrate<TEventType>(string? ruleNameOverride = null) instead. The member currently throws a NotImplementedException. Will be removed in version 6.0.0.'

修正后的配置代码

public static IHostBuilder ConfigureNServiceBus(this IHostBuilder hostBuilder)
{
    // Makes sure JObject is included in the NServiceBus scan
    JObject _ = new();

    var auditQueue = EnvironmentVariableHelper.GetConfigValue(IoC.Configuration, "AuditQueue", "audit");
    var errorQueue = EnvironmentVariableHelper.GetConfigValue(IoC.Configuration, "ErrorQueue", "error");
    // 修正:获取Azure Service Bus专用连接字符串(原代码误用了Blob存储连接字符串)
    var azureServiceBusConnectionString = EnvironmentVariableHelper.GetStringConfigValue("AzureServiceBusConnectionString");
    var azureTableStorageConnectionString = EnvironmentVariableHelper.GetStringConfigValue("BlobStorageConnection");
    var endpointName = EnvironmentVariableHelper.GetStringConfigValue("ENDPOINT_NAME");
    var tableStorageName = endpointName.Replace("-", string.Empty).Replace(".", string.Empty);

    hostBuilder.UseNServiceBus(configuration =>
    {
        var endpointConfiguration = configuration.AdvancedConfiguration;                        
        endpointConfiguration.AuditProcessedMessagesTo(auditQueue);
        endpointConfiguration.SendFailedMessagesTo(errorQueue);
        endpointConfiguration.UseSerialization<NewtonsoftJsonSerializer>();

        // 修正:通过UseTransport获取TransportExtensions实例,正确配置传输
        var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
        transport.ConnectionString(azureServiceBusConnectionString);
        // 正确设置TopicName
        transport.TopicName($"{endpointName}.events");
        // 替换废弃的SubscriptionRuleNamingConvention,使用当前API的SubscriptionNamingConvention
        transport.SubscriptionNamingConvention(type => type.Name.Replace("App.Contracts", string.Empty));

        var conventions = endpointConfiguration.Conventions();
        conventions.DefiningCommandsAs(type => type.Namespace != null && type.Namespace.StartsWith("App.Contracts.Commands"));
        conventions.DefiningEventsAs(type => type.Namespace != null && type.Namespace.StartsWith("App.Contracts.Events"));
                    
        var persistence = endpointConfiguration.UsePersistence<AzureTablePersistence>();
        var tableServiceClient = new TableServiceClient(azureTableStorageConnectionString);
        persistence.UseTableServiceClient(tableServiceClient);
        persistence.DefaultTable(tableStorageName);
                    
        endpointConfiguration.AuditSagaStateChanges(serviceControlQueue: auditQueue);
                    
        ExcludeAssmbliesFromScan(endpointConfiguration);
                    
        endpointConfiguration.EnableInstallers();

        #if DEBUG
        // 修正:通过TransportExtensions配置MaxAutoLockRenewalDuration
        transport.MaxAutoLockRenewalDuration(TimeSpan.FromMinutes(30));
        #endif
    });

    return hostBuilder;
}

关键修改说明

  1. 传输连接字符串修正:原代码错误地将Blob存储连接字符串传给Azure Service Bus传输,需替换为Azure Service Bus的专用连接字符串。
  2. TopicName配置方式:新版本API中需通过endpointConfiguration.UseTransport<AzureServiceBusTransport>()获取TransportExtensions<AzureServiceBusTransport>实例,再调用TopicName扩展方法设置,不能直接实例化AzureServiceBusTransport。
  3. 订阅规则命名替换:原SubscriptionRuleNamingConvention已废弃,在默认拓扑下改用SubscriptionNamingConvention定义订阅规则名称。
  4. 调试模式配置修正:MaxAutoLockRenewalDuration同样需通过TransportExtensions实例的扩展方法设置。

内容的提问来源于stack exchange,提问作者Felipe Siqueira Queiroz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 17:34:57