我有一个 WebApi Controller ,它具有由 AutoFac 在 OWIN 启动类中注入(inject)的服务
builder.Register(c => new MyEntities()).InstancePerRequest();
我也试过
builder.Register(c => new MyEntities()).InstancePerLifetimeScope();
在 Controller 操作中,我调用服务方法来创建新记录,通过 HttpClient 将创建的 ID 传递给外部 api 以获取更多数据,然后使用一些返回数据更新新记录。
[HttpPost, Route("")]
public async Task<IHttpActionResult> MyControllerAction(MyModel model)
{
var id = await _MyService.CreateNewThing(model.SomeId);
var externalData = await CallExternalApiThroughHttpClient(id);
await _MyService.UpdateNewThing(id, externalData);
return Ok();
}
服务代码
public class MyService : IMyService
{
private MyEntities _context;
public MyService(MyEntities context)
{
_context = context;
}
public async Task<int> CreateNewThing(int someId)
{
var thing = new Thing
{
SomeId = someId
};
_context.Things.Add(thing);
await _context.SaveChangesAsync();
return thing.Id;
}
public async Task UpdateNewThing(int id, string externalDataField)
{
var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);
if (thing == null)
{
throw new ServiceNotFoundException("Thing " + transactionId + " not found");
}
thing.ExternalDataField= externalDataField;
await _context.SaveChangesAsync();
}
}
但是我在 UpdateNewThing var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);
InvalidOperationException
System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
看来我不得不放弃注入(inject)上下文、async/await 或使用上下文工厂之类的东西;除非有人能发现我遗漏的一些简单的东西,否则我会继续这个设计。
最佳答案
您的代码在单线程上下文中看起来不错。但是,DbContext
不是线程安全的,我怀疑发生的事情是您在一个线程上执行 CreateNewThing()
,而任务调度程序在这种情况下执行 UpdateNewThing()
在不同的线程上。
无论哪种方式,一个更好的比喻是使用上下文工厂,在本例中将其注入(inject)到 IMyService
中,然后为每个 IMyService
方法创建一个新的MyEntities
上下文在 using()
block 中。
DbContext
的创建成本很低,这就是它们的用途;长期存在的上下文几乎总是不正确的用法。
编辑 1 - 根据要求示例上下文工厂。我倾向于实现一个可以创建多个上下文的通用工厂,但这可能超出了这个问题的范围。
public interface IMyEntitiesFactory
{
MyEntities Create();
}
public class MyEntitiesFactory : IMyEntitiesFactory
{
MyEntities IMyEntitiesFactory.Create()
{
return new MyEntities();
}
}
// For use with unit tests; e.g. pass a mock object to the constructor.
public class TestMyEntitiesFactory : IMyEntitiesFactory
{
private readonly MyEntities _value;
public TestMyEntitiesFactory(MyEntities value)
{
_value = value;
}
MyEntities IMyEntitiesFactory.Create()
{
return _value;
}
}
关于c# - EF + AutoFac + async "The connection' s 当前状态正在连接”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34308008/