使用 Task.Run 的即发即弃方法无效

Fire & Forget method using Task.Run not working

我阅读了很多尝试使用 Task.Run 的代码,但都没有成功。

我想达到的目标:

我试过但不明白为什么它不起作用:


第一版:

protected void btn_Click(object sender, EventArgs e)
{
    // Some actions
    // Should insert a record in database --> OK

    //Tried this call with and without ConfigureAwait(false)
    Task.Run(() => MyClass.doWork()).ConfigureAwait(false);

    // Should insert a record in database --> OK
    // Some actions not blocked by the previous call
}

public static class MyClass
{
    public static void doWork()
    {
        // Should insert a record in database --> NOT INSERTED
    }
}


第二个版本:

protected void btn_Click(object sender, EventArgs e)
{
    // Some actions
    // Should insert a record in database --> OK

    Bridge.call_doWork();

    // Should insert a record in database --> OK
    // Some actions not blocked by the previous call
}

public static class Bridge
{
    public static async Task call_doWork()
    {
        //Tried this call with and without ConfigureAwait(false)
        await Task.Run(() => MyClass.doWork()).ConfigureAwait(false);
    }
}

public static class MyClass
{
    public static void doWork()
    {
        // Should insert a record in database --> NOT INSERTED
    }
}

所以我调用了 Fire & Forget 方法,它应该在数据库中插入一条记录,但是没有插入记录。

调用 Fire & Forget 方法前后的插入已完成。

我不知道如何解决我的问题。

HttpContext在主线程以外的线程中将不可用,因此您不能依赖它。

但是您可以在启动任务时将数据从 HttpContext 传递到您的方法。例如:

Task.Run(() => MyClass.doWork(HttpContext.Current.Session["somedata"])).ConfigureAwait(false);

Why didn't I get an EventViewer event with the HttpContext call? I got one when using HostingEnvironment.QueueBackgroundWorkItem instead of Task.Run.

好的,首先,如果你有 QueueBackgroundWorkItem 可用,你为什么 曾经 使用 Task.Run对于即发即弃的工作?

正如我在我的博客中所描述的那样,using Task.Run for fire-and-forget on ASP.NET is a really bad ideaQueueBackgroundWorkItem 最小 可行的解决方案,并且只有在您接受不可靠性的情况下才会如此。

QueueBackgroundWorkItem 除了 Task.Run 之外,还为您做了一些事情:它用 ASP.NET 运行 时间注册了作品(这最大限度地减少了但并没有消除可能性工作将无法完成),它会捕获异常并为您记录它们(这就是您看到事件通知的原因)。

所以,您看到了一个异常事件,因为 QBWI 正在为您做这件事。而对于 Task.Run 代码,异常将被捕获并放置在返回的 Task 上(应该如此),然后您的代码完全忽略了该任务,从而默默地吞下了异常。

Yes! I use HttpContext to get the Session. But I can't change that without changing a lot of code.

正如其他人所指出的,HttpContext 仅在请求上下文中有效。所以,当你显式 运行 后台代码时,它当然没有请求上下文。根据定义,后台代码必须独立于请求。


但是我认为您忽略了另一个非常重要的注意事项:

public static void doWork()
{
    // Should insert a record in database --> NOT INSERTED
}

如果 doWork 偶尔不执行,您确定您的应用程序完全正常吗?因为后台任务就是这样。 ASP.NET 旨在响应请求,而不是 运行 后台任务。

所以,千载难逢,doWork 应该插入的记录不会出现。如果这是不可接受的,那么您不应该进行即发即弃。