将EventHandler与Entity Framework结合使用:在先前的异步操作完成之前,第二个操作在此上下文上启动

时间:2019-04-22 10:58:26

标签: c# entity-framework events event-handling

我正在尝试根据某些事件更新数据库。每当A生成事件时,B就会执行数据库更新。我不断收到以下例外

“在先前的异步操作完成之前,第二个操作在此上下文上开始。使用await确保在此上下文上调用另一个方法之前,所有异步操作都已完成。不保证任何实例成员都是线程安全的。”

我了解该异常,但是我不知道它来自何处,以及它是否与使用EventHandler有关。

经过长时间搜索:

  • 我确保一切都在等待,以确保没有使用dbcontext进行并行调用
  • 我确保只订阅了一个事件(这是来自其他stackoverflow问题的建议)
  • 我通过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();
}

我想知道导致此问题的原因以及是否有可能解决此问题。

1 个答案:

答案 0 :(得分:0)

是的,您的问题是由于事件处理所致。更具体地说,这是由于goquery造成的。下面的代码行中的两者都属于package main import ( "fmt" "log" "strings" "github.com/PuerkitoBio/goquery" ) func findHeader(d *goquery.Document) string { header := d.Find("h1").Text() return header } func main() { // create from a string data := ` <html> <head> <title>My document</title> </head> <body> <h1>Header</h1> </body> </html>` doc, err := goquery.NewDocumentFromReader(strings.NewReader(data)) if err != nil { log.Fatal(err) } fmt.Println(findHeader(doc)) } 陷阱:

async void

problems with async void之一是调用代码无法知道它何时完成。

如果您真的想对日志消息使用事件(这对我来说似乎有点奇怪),那么您必须让事件只是将日志消息添加到队列中(同步),并有一个单独的“工人”来提取消息走出队列,然后将它们异步发送到数据库。