【发布时间】:2016-01-14 05:26:44
【问题描述】:
在 ASP.NET MVC 应用程序中,我收到以下错误消息,说明我的一个控制器方法使用了我的 Entity Framework 上下文。
在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用 'await' 确保在此上下文中调用另一个方法之前所有异步操作都已完成。不保证任何实例成员都是线程安全的。
我知道您不能并行运行查询,而且一切似乎都在正常等待。如果我调试程序并单步检查从 EF 返回的一些数据,那么它可以工作,可能是因为这会强制查询完成。
编辑如果我在控制器方法中的 null 检查处放置断点并检查 shipmentDetail 的数据,则不会引发异常。
以下是代码片段:
控制器方法:
[Route("{id:int}/Deliveries")]
public async Task<ActionResult> DeliveryInfo(int id)
{
var shipmentDetail = await db.ShipmentDetails.SingleOrDefaultAsync(s => s.Id == id);
if (shipmentDetail == null)
return HttpNotFound(string.Format("No shipment detail found with id {0}", id));
var model = await DeliveryInfoModel.CreateModel(db, shipmentDetail);
return View("DeliveryInfo", model);
}
CreateModel 方法:
public static async Task<DeliveryInfoModel> CreateModel(Context db, ShipmentDetail shipment)
{
DeliveryInfoModel model = new DeliveryInfoModel()
{
ShipmentInfo = shipment
};
//initialize processing dictionary
Dictionary<int, bool> boxesProcessed = new Dictionary<int, bool>();
List<DeliveryBoxStatus> statuses = new List<DeliveryBoxStatus>();
for (int i = 1; i <= shipment.BoxCount; i++ )
{
boxesProcessed.Add(i, false);
}
//work backwards through process
//check for dispositions from this shipment
if(shipment.Dispositions.Count > 0)
{
foreach (var d in shipment.Dispositions)
{
DeliveryBoxStatus status = new DeliveryBoxStatus()
{
BoxNumber = d.BoxNumber,
LastUpdated = d.Date,
Status = d.Type.GetDescription().ToUpper()
};
statuses.Add(status);
boxesProcessed[d.BoxNumber] = true;
}
}
//return if all boxes have been accounted for
if (boxesProcessed.Count(kv => kv.Value) == shipment.BoxCount)
{
model.BoxStatuses = statuses;
return model;
}
//check for deliveries
if(shipment.Job_Detail.Count > 0)
{
foreach (var j in shipment.Job_Detail.SelectMany(d => d.DeliveryInfos))
{
DeliveryBoxStatus status = new DeliveryBoxStatus()
{
BoxNumber = j.BoxNumber,
LastUpdated = j.Job_Detail.To_Client.GetValueOrDefault(),
Status = "DELIVERED"
};
statuses.Add(status);
boxesProcessed[j.BoxNumber] = true;
}
}
//check for items still in processing & where
foreach (int boxNum in boxesProcessed.Where(kv => !kv.Value).Select(kv => kv.Key))
{
//THIS LINE THROWS THE EXCEPTION
var processInfo = await db.Processes.Where(p => p.Jobs__.Equals(shipment.Job.Job__, StringComparison.InvariantCultureIgnoreCase) && p.Shipment == shipment.ShipmentNum && p.Box == boxNum)
.OrderByDescending(p => p.date)
.FirstOrDefaultAsync();
//process returned data
//...
}
model.BoxStatuses = statuses;
return model;
}
我不完全确定这是因为在控制器中进行的查询,还是因为在循环中进行的查询未完成导致此行为。由于 EF 的懒惰,或者 async/await 在这种情况下如何工作,我有什么不明白的地方吗?我有很多其他方法和控制器可以进行异步 EF 调用,以前没有遇到过这种情况。
编辑
我的上下文使用 Ninject 作为我的 IoC 容器注入到我的控制器中。这是它在 NinjectWebCommon 的 RegisterServices 方法中的配置:
kernel.Bind<Context>().ToSelf().InRequestScope();
【问题讨论】:
-
我怀疑你的错误来自其他地方,这段代码应该没问题。 A) 您的
db是否与其他视图/视图模型共享? B) 你有没有用调试器单步调试它,看看它是否仍然抛出? -
A) 不,它没有被共享,它被注入到控制器并且只在那里使用,这些是使用
db上下文的仅有的 2 个操作用于此 http 请求。 B)如果我检查从 EF 返回的数据(我在问题中提到过),则使用调试器不会抛出,否则会抛出。 -
你能详细说明它是如何注入的吗?它是从 IoC 容器注入的吗?如果是这样,您的 IoC 注册是如何配置的?
-
我使用 Ninject 作为我的 IoC 容器。我会将上下文的配置添加到我的问题中
-
您的
db变量是如何声明的?你可能做到了static?
标签: c# asp.net-mvc entity-framework asynchronous async-await