我在每个网络API请求的基础上使用Simple Injector注册我的DbContext:
container.RegisterWebApiRequest<IModelContext, ModelContext>();
但是也要为每个Web请求创建一个委托过滤器:
container.RegisterAll<DelegatingHandler>(
...
typeof(DelegatingHandlerProxy<TraceRequestHandler>)
...
);
保存有关db中请求的一些信息:
public class TraceRequestHandler(ITraceRequestRepository r) : DelegateHandler
public class EntityTraceRequestRepository(IModelContext c) : ITraceRequestRepository
导致各种EF多线程异常的原因:
创建模型时无法使用上下文。如果在OnModelCreating方法中使用上下文,或者同时由多个线程访问相同的上下文实例,则可能抛出此异常。请注意,DbContext和相关类的实例成员不保证是线程安全的。
在上一次异步操作完成之前,在此上下文中启动了第二个操作。使用&#39;等待&#39;确保在调用此上下文中的另一个方法之前已完成任何异步操作。不保证任何实例成员都是线程安全的。
连接未打开。
ObjectContext实例已被释放,不能再用于需要连接的操作
在控制器/存储库中,例如:
public ProductController(IProductRepository r) : ApiController
public EntityProductRepository(IModelContext c) : IProductRepository
删除请求跟踪后,一切正常。
如何为“通用”单独注册数据库上下文&#39;模块和基础设施模块?
答案 0 :(得分:1)
错误出现在您未在问题中显示的代码中,InfrastructureDelegatingHandler
:
internal sealed class InfrastructureDelegatingHandler : DelegatingHandler {
private readonly IDbContext _dbContext;
public InfrastructureDelegatingHandler(IDbContext dbContext) {
_dbContext = dbContext;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken) {
Task.Factory.StartNew(() => TraceRequest(request));
return base.SendAsync(request, cancellationToken);
}
private void TraceRequest(HttpRequestMessage request) {
DbRawSqlQuery<string> query =
((EfDbContext)_dbContext).Database.SqlQuery<string>(
"select name from sys.indexes");
Console.WriteLine(String.Join(",", query.ToArray()));
}
}
问题出在以下几行:
Task.Factory.StartNew(() => TraceRequest(request));
在此行中,您将启动调用TraceRequest的新任务。然而,TraceRequest使用_dbContext
,您永远不会等待创建的任务,这意味着它将在后台运行。换句话说,您的EfDbContext
同时来自多个线程。
将代码更改为以下内容时,您的问题将消失:
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken) {
await Task.Factory.StartNew(() => TraceRequest(request));
var message = await base.SendAsync(request, cancellationToken);
return message;
}