A NullReferenceException deep inside EntityFramework code is thrown (EF bug?), but my question is about Entity Framework (v5) and WebAPI asynchronous controller action.
A repro would be hard to recreate here, but the code in essence does the following:
public class AController : ApiController
{
private IUow _uow; //among other things, a DbContext
// DI ctor
public AController(IUow uow)
{
_uow = uow;
}
[HttpPost]
public async Task<HttpResponseMessage> Post(Model model)
{
Entity e = _uow.Entity.GetById(model.id);
await IO_Ops_Async(model);
new ModelAdapter().UpdateEntity(entity, model);
_uow.Commit(); <- EXCEPTION THROWN DURING THIS CALL - see below
... // do something with the return result
}
}
Inside Commit()
, just before DbContext.SaveChanges()
, we loop through all DbChangeTracker.Entries()
to set some common properties. But it is the Entries()
that errors before a single loop with a NullReferenceException
deep inside System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
Below is the call stack. It's all Framework code and it feels like a bug, but my question really is if the above async/await use in-between DbContext calls is permitted. At no point we multi-thread - async/await is only used because there are a few IO operations that we can execute using the async/await facility (a couple of Httpclient downloads + some async disk I/O).
System.NullReferenceException: Object reference not set to an instance of an object.\r\n
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.EntityReference`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.EntityReference`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)\r\n
at System.Data.Objects.ObjectStateManager.PerformAdd(IEntityWrapper wrappedOwner, RelatedEnd relatedEnd, IEntityWrapper entityToAdd, Boolean isForeignKeyChange)\r\n
at System.Data.Objects.ObjectStateManager.PerformAdd(IList`1 entries)\r\n
at System.Data.Objects.ObjectStateManager.DetectChanges()\r\n
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)\r\n
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()\r\n