在ASP.NET Core中做出响应后做一些工作

Jea*_*ean 5 entity-framework asp.net-core-mvc asp.net-core

我有一个使用EFCore的ASP.NET Core网站。我想做一些工作,例如登录到数据库,但是在将响应发送给用户以便更快回答之后。

我可以在其他线程中执行此操作,但是由于对DbContext的异步访问,我不确定它是否安全。有什么推荐的方法吗?

public async Task<IActionResult> Request([FromForm]RequestViewModel model, string returnUrl = null)
{
    try 
    {
      var newModel = new ResponseViewModel(model);
      // Some work 
      return View("RequestView",newModel)
    }
    finally
    {
        // Some analysis on the request
        // I would like to defer this part
        await Log(model);
    }
}
Run Code Online (Sandbox Code Playgroud)

原因之一是我想调用一个Web服务(地理编码),它不需要回答,但是可以很好地处理日志(我需要坐标的城市/国家/地区)。

Jea*_*ean 17

我看到这从未得到回答,但实际上有一个解决方案。简单的解决方案:

public async Task<IActionResult> Request([FromForm]RequestViewModel model, string returnUrl = null)
{
    try 
    {
      var newModel = new ResponseViewModel(model);
      // Some work 
      return View("RequestView",newModel)
    }
    finally
    {
        Response.OnCompleted(async () =>
        {
            // Do some work here
            await Log(model);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

安全解决方案,OnCompleted过去在发送响应之前调用,因此延迟响应:

public static void OnCompleted2(this HttpResponse resp, Func<Task> callback)
{
    resp.OnCompleted(() =>
    {
        Task.Run(() => { try { callback.Invoke(); } catch {} });
        return Task.CompletedTask;
    });
}
Run Code Online (Sandbox Code Playgroud)

并打电话 Response.OnCompleted2(async () => { /* some async work */ })

  • 只是指出,从 ASP.NET Core 2.1.0-preview2 开始,发送响应之前调用 OnCompleted 的 bug 已得到修复,因此如果您使用的是更高版本,第一个解决方案就可以:[GitHub 问题](https:// /github.com/aspnet/KestrelHttpServer/issues/2035) (10认同)

Joh*_*olz 5

基于Jeans 答案以及模式上的问答try - return - finally,可以删除tryfinally块(如果您真的不想捕获异常)。

这导致以下代码:

public async Task<IActionResult> Request([FromForm] RequestViewModel model, string returnUrl = null)
{
    var newModel = new ResponseViewModel(model);

    // Some work 

    Response.OnCompleted(async () =>
    {
        // Do some work here
        await Log(model);
    });

    return View("RequestView", newModel);
}
Run Code Online (Sandbox Code Playgroud)