AzureFunctions.Autofac проблема внедрения безопасных потоковых зависимостей - PullRequest
0 голосов
/ 02 июня 2019

Я использую AzureFunctions.Autofac для добавления в мой веб-интерфейс функций Azure.Пример конфигурации:

  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);
        }

Но я продолжаю получать эту ошибку:

Вторая операция началась в этом контексте до завершения предыдущей асинхронной операции.Используйте 'await', чтобы убедиться, что все асинхронные операции завершены, прежде чем вызывать другой метод в этом контексте.Любые члены экземпляра не гарантированно являются потокобезопасными.

Я убедился, что async и await используются правильно, поэтому следование рекомендациям в сообщении об ошибке не помогает их исправить.Проблема в том, что IDbContext не соблюдает InstancePerLifetimeScope, как ожидалось.Это происходит потому, что у меня в классе InventoryFunctions более одного метода?Или AzureFunctions.Autofac не безопасен для потоков?

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Я собирался ответить на этот SO: Autofac - InstancePerHttpRequest vs InstancePerLifetimeScope , в котором говорилось, что InstancePerLifetimeScope был не -ASP.NET-эквивалентом InstancePerRequest.

, с которым я говорилразработчики и они сказали, что правда состоит в том, что получение одного DbContext на HttpRequest было поведением по умолчанию, когда вы просто регистрируетесь с использованием builder.RegisterType<SecretCompanyContext>.As<IDbContext>(), поэтому существует некоторая дезинформация.

Таким образом, решение вместо использования

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

или

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

нужно просто использовать

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

, если целью является один экземпляр на HTTP-запрос.

1 голос
/ 03 июня 2019

Измените регистрацию DbContext следующим образом:

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

Вы можете найти более глубокое мое объяснение, почему это происходит здесь .

...