在Entity Framework(v5)和WebAPI异步控制器操作中,会抛出一个深层次的NullReferenceException异常(EF bug?)。但我的问题是关于Entity Framework的。
这里很难重现,但代码本质上做了以下几件事:
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
}
}
在
Commit()
内部,在DbContext.SaveChanges()
之前,我们循环遍历所有的DbChangeTracker.Entries()
来设置一些公共属性。但是在单个循环之前,Entries()
出现了一个NullReferenceException
,深入到System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
中。
以下是调用堆栈。这都是框架代码,感觉像是一个bug,但我的问题实际上是在DbContext调用之间是否允许使用以上async/await。我们没有多线程 - async/await只是因为有一些IO操作可以使用async/await功能执行(一些HttpClient下载+一些异步磁盘IO)。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