Do some work after the response in ASP.NET Core

前端 未结 5 1669
梦如初夏
梦如初夏 2021-02-08 03:31

I have an ASP.NET Core website, using EFCore. I would like to do some work like logging to the database, but after having sent the response to the user in order to answer faster

相关标签:
5条回答
  • 2021-02-08 03:34

    There's no out of the box way to do what you want.

    But, here's a possible approach:

    1. Have a queue and a worker (thread or process)
    2. Just before the request is sent back to the client, add a message in that queue
    3. The worker will pick up that message at some point in the future, and process it.

    Since the worked runs somewhere else and not on the request thread, the server can complete the request thread and the worker can do what's left.

    0 讨论(0)
  • 2021-02-08 03:48

    Try using Hangfire. Hangfire is an easy way to perform background processing in .NET and .NET Core applications. No Windows Service or separate process required. Backed by persistent storage. Open and free for commercial use.

    You could do something like

    var jobId = BackgroundJob.Enqueue(() => Log(model));
    

    And here is my blog post on using HangFire in ASP.NET Core

    0 讨论(0)
  • 2021-02-08 03:53

    Create a new class that inherits from ActionFilterAttribute, overwrite the OnResultExecuted method to perform the logging and then apply your attribute class to the controller actions you want to do logging.

    0 讨论(0)
  • 2021-02-08 03:54

    Building on Jeans answer and a question and answer on the try - return - finally pattern, the try and finally blocks can be removed (if you don't really want to catch an exception).

    This leeds to the following code:

    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);
    }
    
    0 讨论(0)
  • 2021-02-08 04:00

    I see this has never been answered, but actually have a solution. The simple solution:

    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);
            });
        }
    }
    

    The secure solution, as OnCompleted used to be called before the response being sent, so delaying the response:

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

    and call Response.OnCompleted2(async () => { /* some async work */ })

    0 讨论(0)
提交回复
热议问题