我试图根据一些事件更新我的数据库。每当A生成事件时,B将执行数据库更新。我一直得到以下异常:
“在上一次异步操作完成之前,第二个操作在此上下文中启动。使用await
确保在此上下文上调用另一个方法之前已完成任何异步操作。不保证所有实例成员都是线程安全的。”
我理解异常,但我不知道它来自何处,以及它是否与使用EventHandler有关。
经过长时间搜索:
async/await
订阅了这个活动Task.WaitAll()
class A {
public event EventHandler<LogArgs> LogEvent;
public void WorkInA() {
.....
this.SendLogEvent();
.....
this.SendLogEvent();
.....
}
private void SendLogEvent() {
this.LogEvent(this, args);
}
}
class B {
private A a;
public async void Init() {
//Before: a.LogEvent += LogEventToDB;
a.LogEvent += async (s, e) => await LogEventToDB(s, e);
}
public void DoWork() {
.....
a.WorkInA();
.....
}
private async Task LogEventToDB(object sender, LogMessageEventArgs e) {
.....
await this.unitOfWork.SaveAsync();
.....
}
}
//Inside unitOfWork
public async Task SaveAsync()
{
await this.context.SaveChangesAsync();
}
我想知道导致此问题的原因以及是否可以修复它。
是的,您的问题是由于事件处理造成的。更具体地说,这是由于async void
。以下两行代码都属于async void
陷阱:
//Before: a.LogEvent += LogEventToDB;
a.LogEvent += async (s, e) => await LogEventToDB(s, e);
其中一个problems with async void
是调用代码无法知道它何时完成。
如果你真的想将事件用于日志消息(这对我来说有点奇怪),那么你必须让事件只是将日志消息添加到队列中(同步),并让一个单独的“工作者”将消息从队列并将它们发送到数据库(异步)。