Pau*_*wat 5 c# autofac async-await entity-framework-6 asp.net-web-api2
我有一个WebApi控制器,它在OWIN Startup类中有AutoFac注入的服务
builder.Register(c => new MyEntities()).InstancePerRequest();
Run Code Online (Sandbox Code Playgroud)
我也试过了
builder.Register(c => new MyEntities()).InstancePerLifetimeScope();
Run Code Online (Sandbox Code Playgroud)
在控制器操作中,我调用服务方法来创建新记录,通过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();
}
Run Code Online (Sandbox Code Playgroud)
服务代码
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();
}
}
Run Code Online (Sandbox Code Playgroud)
但是我InvalidOperationException在UpdateNewThing中得到了一个var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);
System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
Run Code Online (Sandbox Code Playgroud)
好像我不得不放弃注入上下文,异步/等待或使用像contextfactory这样的东西; 除非有人能发现我错过的简单内容,否则我会继续这个设计.
您的代码在单线程上下文中看起来很好。但是,DbContext它不是线程安全的,我怀疑发生的情况是您CreateNewThing()在一个线程上执行,而任务调度程序在这种情况下UpdateNewThing()在不同的线程上执行。
无论哪种方式,更好的比喻是使用上下文工厂,IMyService在本例中将其注入到您的上下文工厂中,然后为每个方法在块中IMyService创建一个新的上下文。MyEntitiesusing()
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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
979 次 |
| 最近记录: |