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

.NET 7独立Azure函数部署后依赖注入失败(本地正常)

问题:Azure函数部署后依赖注入失败,本地运行正常

我有一个Web API项目和独立的Azure函数项目,两者依赖注入(DI)配置几乎一致,还提取了扩展方法来加载依赖。函数由ServiceBus消息触发,本地调试完全正常,但部署到Azure后,发送消息就会报DI错误,无法实例化自定义类。

消息监听函数代码

public class ProcessingAnalyseDocumentsConsumer {

    private readonly ILogger<ProcessingAnalyseDocumentsConsumer> _logger;
    private readonly FormRecogniserService _formRecogniserService;
    private readonly ReprocessEncounterService _reprocessEncounterService;
    private readonly DataContext _context;

    public ProcessingAnalyseDocumentsConsumer(
        ILogger<ProcessingAnalyseDocumentsConsumer> logger,
        FormRecogniserService formRecogniserService,
        ReprocessEncounterService reprocessEncounterService,
        DataContext context) {
        _logger = logger;
        _formRecogniserService = formRecogniserService;
        _reprocessEncounterService = reprocessEncounterService;
        _context = context;
    }

    [Function("ProcessingAnalyseDocumentsConsumer")]
    public async Task RunAsync(
        [ServiceBusTrigger(Constants.QUEUES_PROCESSING_ANALYSIS_DOCUMENTS, Connection = "ServiceBusConnection")]
        ReprocessSingleDoc message) {
        
        _logger.LogInformation($"C# ServiceBus queue trigger function processed message: {JsonConvert.SerializeObject(message)}");

        var item = _context.LocationCities.FirstOrDefault();
        _logger.LogInformation($"Found item in db: {JsonConvert.SerializeObject(item)}");

    }
}

Program.cs配置代码

var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(async (hostContext, services) => {
    var configuration = hostContext.Configuration;
    var connectionString = configuration["DefaultConnection"];
    var env = hostContext.HostingEnvironment;

    services.AddDbContext<DataContext>(dbContextOptions =>
        dbContextOptions
        .UseLazyLoadingProxies()
        .UseSqlServer(
            connectionString,
            b => b.MigrationsAssembly("WEBAPIPROJECTASSEMBLY"))
        );

    if (!env.IsDevelopment()) {

        services.AddAzureClients(azureClientFactoryBuilder => {
            azureClientFactoryBuilder.AddSecretClient(configuration.GetSection("KeyVault"));
        });

        Console.WriteLine("adding azure vault");
        services.AddSingleton<IKeyVaultService, KeyVaultService>();
    }
    else {
        Console.WriteLine("adding debug vault");
        services.AddSingleton<IKeyVaultService, DebugKeyVaultService>();
    }

    await services.AddSensitiveServicesAsync(); //扩展方法,用于添加服务
    services.AddHttpContextAccessor(); //使HttpContext可用
    services.ServiceDependencies(); //扩展方法,用于添加服务
});

await host.Build().RunAsync();

DI扩展方法代码

public static async Task<IServiceCollection> AddSensitiveServicesAsync(this IServiceCollection services) {

    var serviceProvider = services.BuildServiceProvider();
    var keyVault = serviceProvider.GetService<IKeyVaultService>();

    if (keyVault == null) {
        throw new NullReferenceException(nameof(keyVault));
    }

    await services.AddBlobStorage(keyVault);
    await services.AddFormRecogniserService(keyVault);
    return services;
}

public static async Task<IServiceCollection> AddBlobStorage(
    this IServiceCollection services,
    IKeyVaultService keyVault) {

    var blobStorageConnectionString = await keyVault.GetSecret("blob-storage-connection");
    services.AddTransient(t => new BlobStorageService(blobStorageConnectionString));
    return services;
}

public static async Task<IServiceCollection> AddFormRecogniserService(
    this IServiceCollection services,
    IKeyVaultService keyVault) {

    var secret_key = await keyVault.GetSecret("form-recogniser-key");
    var secret_endpoint = await keyVault.GetSecret("form-recogniser-endpoint");

    var serviceProvider = services.BuildServiceProvider();
    var blobStorage = serviceProvider.GetService<BlobStorageService>();

    if (blobStorage == null) {
        throw new NullReferenceException(nameof(blobStorage));
    }

    services.AddTransient(t => new FormRecogniserService(secret_key, secret_endpoint, blobStorage));
    return services;
}

异常信息

结果:失败 异常信息:System.InvalidOperationException: 尝试激活'medimore_azure_functions.Messaging.ProcessingAnalyseDocumentsConsumer'时,无法解析类型'medimore_azure.FormRecogniserService'的服务。 at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters) at Microsoft.Azure.Functions.Worker.DefaultFunctionActivator.CreateInstance(Type instanceType, FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionActivator.cs:line 23 at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionInvoker2.CreateInstance(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionInvoker.cs:line 26 at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 30 at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13 at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88 堆栈跟踪: at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters) at Microsoft.Azure.Functions.Worker.DefaultFunctionActivator.CreateInstance(Type instanceType, FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionActivator.cs:line 23 at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionInvoker2.CreateInstance(FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionInvoker.cs:line 26 at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 30 at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13 at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88

补充说明

  • 本地调试完全正常,WebAPI项目无论本地还是Azure部署都正常,只有Azure函数部署后出问题
  • 试过移除DebugKeyVault切换逻辑,部署后依然报错
  • 自定义服务依赖KeyVault密钥,所以用了异步扩展方法,本地和WebAPI都没问题
  • 只要移除所有自定义服务注入,只保留Logger,函数就能正常运行

解决方案

1. 停止在DI配置中重复构建ServiceProvider

你的扩展方法里多次调用services.BuildServiceProvider(),会创建独立的服务容器实例,导致后续注册的服务无法被主容器识别。Azure函数宿主环境对容器生命周期的管控更严格,这直接引发了解析失败,而本地环境的容器行为掩盖了问题。

修改扩展方法,改用工厂模式延迟解析依赖,不要提前构建容器:

public static async Task<IServiceCollection> AddSensitiveServicesAsync(this IServiceCollection services) {
    // 用工厂委托延迟创建BlobStorageService,避免提前构建容器
    services.AddTransient<BlobStorageService>(async sp => {
        var keyVault = sp.GetRequiredService<IKeyVaultService>();
        var connString = await keyVault.GetSecret("blob-storage-connection");
        return new BlobStorageService(connString);
    });

    // 同样用工厂模式创建FormRecogniserService
    services.AddTransient<FormRecogniserService>(async sp => {
        var keyVault = sp.GetRequiredService<IKeyVaultService>();
        var secretKey = await keyVault.GetSecret("form-recogniser-key");
        var endpoint = await keyVault.GetSecret("form-recogniser-endpoint");
        var blobStorage = sp.GetRequiredService<BlobStorageService>();
        return new FormRecogniserService(secretKey, endpoint, blobStorage);
    });

    return services;
}

2. 验证KeyVault访问权限

在Azure门户中,确认函数应用的托管标识已被授予KeyVault的机密读取权限。如果权限缺失,会导致密钥获取失败,进而无法实例化依赖服务,最终表现为DI解析失败。

3. 对齐依赖包版本

确保Azure函数相关包(Microsoft.Azure.Functions.Worker、Microsoft.Azure.Functions.Worker.Sdk等)与WebAPI项目的依赖包版本一致,版本不兼容可能导致DI行为差异。

4. 优先使用接口注入

虽然直接注入具体类型本身没问题,但推荐使用接口(比如IFormRecogniserService),符合依赖倒置原则的同时,也能避免类型注册相关的解析问题:

// 修改构造函数参数为接口类型
public ProcessingAnalyseDocumentsConsumer(
    ILogger<ProcessingAnalyseDocumentsConsumer> logger,
    IFormRecogniserService formRecogniserService,
    IReprocessEncounterService reprocessEncounterService,
    DataContext context) {
    // ...
}

// DI注册时添加接口与实现的映射
services.AddTransient<IFormRecogniserService, FormRecogniserService>();

内容的提问来源于stack exchange,提问作者spaceman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:14:50