【问题标题】:AzureFunctions.Autofac threadsafe dependency injection issueAzureFunctions.Autofac 线程安全依赖注入问题
【发布时间】:2019-10-18 02:04:57
【问题描述】:

我正在使用 AzureFunctions.Autofac 注入我的 Azure Functions Web api。配置示例:

  public class DIConfig
    {
        public DIConfig()
        {
            DependencyInjection.Initialize(builder =>
            {
                // DAL
                builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerLifetimeScope();
                builder.RegisterType<SecretCompanyContext>().InstancePerLifetimeScope();
                builder.RegisterType<SecretCompanyContext>().As<ICartContext>().InstancePerLifetimeScope();
                builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope();

                // Services               
                builder.RegisterType<InventoryServices>().As<IInventoryServices>().InstancePerLifetimeScope();

                // Controllers ported from ASP.NET MVC Web API
                builder.RegisterType<InventoryController>().InstancePerLifetimeScope();
            });
        }

然后是我的 Azure 函数,我有一个定义 API 中所有方法的类

    [DependencyInjectionConfig(typeof(DIConfig))]
    public class InventoryFunctions : FunctionsApi
    {
        [FunctionName("GetProductsByCategory")]
        // /inventory/categories/{id}/products
        public static async Task<HttpResponseMessage> GetProductsByCategory(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = "inventory/categories/{id}/products")]
            HttpRequestMessage req,
            TraceWriter log,
            int id,
            [Inject] InventoryController controller)
        {
            // do stuff
            var result = await controller.GetProductsByCategory(id);
            return JsonResponse(result, HttpStatusCode.OK);
        }

        [FunctionName("GetInventoryBySku")]
        // /inventory/skus?sku=ASDF&sku=ASDG&sku=ASDH
        public static async Task<HttpResponseMessage> GetInventoryBySku(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = "inventory")]
            HttpRequestMessage req,
            TraceWriter log,
            [Inject] InventoryController controller)
        {
            // do stuff
            var result = await controller.QueryInventoryBySkuList(skuList);
            return JsonResponse(result, HttpStatusCode.OK);
        }

        [FunctionName("UpdateProductsQuantity")]
        // /inventory
        // Post
        public static async Task<HttpResponseMessage> UpdateProductsQuantity(
            [HttpTrigger(AuthorizationLevel.Function, "put", Route = "inventory")]
            HttpRequestMessage req,
            TraceWriter log,
            [Inject] InventoryController controller)
        {
            // do stuff
            var inventoryProducts = await req.Content.ReadAsAsync<List<InvProductOperation>>();
            var result = await controller.UpdateAvailableProductsQuantity(inventoryProducts);
            return JsonResponse(result, HttpStatusCode.OK);
        }

但我不断收到此错误:

第二个操作在前一个上下文之前开始 异步操作完成。使用“等待”来确保 任何异步操作在调用之前都已完成 在这种情况下的另一种方法。任何实例成员都不是 保证是线程安全的。

我已验证asyncawait 使用正确,因此遵循错误消息的建议并不能修复它。问题似乎是IDbContext 没有像预期的那样尊重InstancePerLifetimeScope。发生这种情况是因为我的InventoryFunctions 类中有多个方法吗?还是 AzureFunctions.Autofac 不是线程安全的?

【问题讨论】:

  • 您使用的是 Azure Function v1 还是 v2? v2 原生支持 DI。
  • @Thomas 使用本机 IoC 不会改变任何东西。这取决于正在注册的DbContext 使用的范围。

标签: c# entity-framework dependency-injection azure-functions autofac


【解决方案1】:

把DbContext的注册改成这样:

 builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();

你可以找到我对为什么会发生这种情况的更深入的解释here

【讨论】:

  • 如果这对您不起作用,您必须在 IDbContext 的注册中创建另一个上下文。
【解决方案2】:

我是这样回答的:Autofac - InstancePerHttpRequest vs InstancePerLifetimeScope,它说InstancePerLifetimeScopeInstancePerRequest 的非 ASP.NET 等价物。

我与开发人员交谈过,他们说事实是,当您只需使用 builder.RegisterType&lt;SecretCompanyContext&gt;.As&lt;IDbContext&gt;() 注册时,每个 HttpRequest 获取一个 DbContext 是默认行为,因此存在一些错误信息。

所以解决方案是,而不是使用

builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();

builder.RegisterType<SecretCompanyContext>().As<IDbContext>().InstancePerLifetimeScope();

应该只使用

builder.RegisterType<SecretCompanyContext>().As<IDbContext>();

如果目标是每个 HTTP 请求一个实例。

【讨论】:

  • 那有什么解决办法呢?
  • @alsami 见上文。
猜你喜欢
  • 1970-01-01
  • 2015-11-21
  • 2014-12-27
  • 2015-04-22
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
  • 2012-10-22
相关资源
最近更新 更多