Я использую AzureFunctions.Autofac для внедрения в мой веб-API функций 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);
}
Но я продолжаю получать эту ошибку:
A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
Я проверил, что async и await используются правильно, поэтому следование рекомендациям в сообщении об ошибке не исправит ситуацию. Похоже, проблема в том, что IDbContext не соблюдает InstancePerLifetimeScope, как ожидалось. Это происходит из-за того, что в моем классе InventoryFunctions есть более одного метода? Или AzureFunctions.Autofac не является потокобезопасным?
@Thomas, использующий собственный IoC, ничего не изменит. Это зависит от области, используемой для регистрируемого DbContext.





Измените регистрацию DbContext на это:
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();
Вы можете найти мое более глубокое объяснение, почему это происходит здесь.
Если это не сработало для вас, вы должны создать другой контекст в этой регистрации IDbContext.
Я исходил из этого SO-ответа: Autofac — InstancePerHttpRequest против 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-запрос.
Так какое же решение в этом?
@alsami См. выше.
Вы используете функцию Azure v1 или v2? v2 имеет встроенную поддержку DI.