AzureFunctions.Autofac 线程安全依赖注入问题
AzureFunctions.Autofac threadsafe dependency injection issue
我正在使用 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 函数,我有一个 class 定义了 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
class 中有不止一种方法吗?或者 AzureFunctions.Autofac 不是线程安全的?
将 DbContext 的注册更改为:
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();
关于为什么会发生这种情况,您可以找到我的更深入的解释 here。
我正在按照这个 SO 回答: 说 InstancePerLifetimeScope
是 non-ASP.NET 等同于 InstancePerRequest
.
我和开发人员谈过,他们说事实是当你简单地使用 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 请求一个实例。
我正在使用 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 函数,我有一个 class 定义了 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
class 中有不止一种方法吗?或者 AzureFunctions.Autofac 不是线程安全的?
将 DbContext 的注册更改为:
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();
关于为什么会发生这种情况,您可以找到我的更深入的解释 here。
我正在按照这个 SO 回答: 说 InstancePerLifetimeScope
是 non-ASP.NET 等同于 InstancePerRequest
.
我和开发人员谈过,他们说事实是当你简单地使用 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 请求一个实例。