EF + AutoFac + async "The current connection status is connecting"

I have a WebApi controller that has services introduced by AutoFac in the OWIN startup class

builder.Register(c => new MyEntities()).InstancePerRequest(); 

I also tried

 builder.Register(c => new MyEntities()).InstancePerLifetimeScope(); 

In the controller action, I call the service method to create a new record, pass the identifier created for the external api through HttpClient to get some more data, and then update the new record with some returned data.

 [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(); } 

service code

 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(); } } 

But I get an InvalidOperationException in UpdateNewThing var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);

 System.InvalidOperationException: The connection was not closed. The connection current state is connecting. 

It seems that I should refuse to enter context, async / await or use something like contextfactory; if someone cannot find something simple that I missed, it will allow me to continue this project.

+5
source share
1 answer

Your code looks great in a single-threaded context. However, DbContext not thread safe, and I suspect that you are executing CreateNewThing() in one thread, and the task scheduler in this case is executing UpdateNewThing() in another thread.

In any case, the best metaphor is to use the factory context, which you enter in your IMyService in this case, and then for each IMyService method IMyService you create a new MyEntities context in using() .

DbContext cheap to create, and that is how they are designed to be used; long-lived contexts are almost always misuse.

Edit 1 is an example of a factory context on request. I tend to implement a common factory that can create multiple contexts, but is probably beyond the scope of this question.

 public interface IMyEntitiesFactory { MyEntities Create(); } public class MyEntitiesFactory : IMyEntitiesFactory { MyEntities IMyEntitiesFactory.Create() { return new MyEntities(); } } // For use with unit tests; eg 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; } } 
+1
source

Source: https://habr.com/ru/post/1238356/


All Articles