AzureFunctions.Autofac线程安全依赖项注入问题

时间:2019-06-02 02:09:47

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

我正在使用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不是线程安全的?

2 个答案:

答案 0 :(得分:1)

将DbContext的注册更改为此:

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

您可以找到关于为什么发生这种情况的更深入的解释here

答案 1 :(得分:1)

我正在回答这个问题:Autofac - InstancePerHttpRequest vs InstancePerLifetimeScope,它说InstancePerLifetimeScopeInstancePerRequest的非ASP.NET等效。

我与开发人员交谈,他们说的事实是,当您仅使用builder.RegisterType<SecretCompanyContext>.As<IDbContext>()注册时,默认情况下,每个HttpRequest获取一个DbContext是默认行为,所以那里存在一些错误信息。

解决方法是,而不是使用

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

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

一个人应该使用

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

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