How to achieve non-blocking processing in a Web API method?

Frank Nátán 25 Reputation points
2023-03-30T11:33:08.0466667+00:00

I have a Web API with the MyWebApiMethod in it. Inside this method I want the following to happen:

  1. Start LogicA, wait for it to finish and then proceed to step 2.
  2. Start LogicB and proceed to step 3. without waiting for LogicB to finish
  3. Return an OK response.

How do I achieve this behavior in the most convenient way? Should I use dreaded async void? Should I use threading? Should I utilize a message queue? What would be a simple an good solution?

public IActionResult MyWebApiMethod(MyRequest request)
{
    LogicA(request);
    LogicB(request); // I don't want to wait for this to finish.
    return Ok();
}
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,078 questions
0 comments No comments
{count} votes

4 answers

Sort by: Most helpful
  1. jlinsey628 0 Reputation points
    2023-03-30T11:46:27.1366667+00:00

    To achieve the desired behavior, you can use asynchronous programming with the async and await keywords in C#. Here is an example of how you can modify your code to achieve this:

    public async Task<IActionResult> MyWebApiMethod(MyRequest request)
    {
        await LogicA(request);
        _ = LogicB(request); // Start LogicB but don't wait for it to finish
        return Ok();
    }
    In this modified code, 
    It's generally not recommended to use 
    Threading and message queues are also options for achieving this behavior, but they may be more complex and introduce additional overhead. Using asynchronous programming with 
    

  2. Ed Harris 25 Reputation points
    2023-03-30T13:36:38.9166667+00:00

    Dear Frank Nátán,

    Thank you for your question about ASP.NET APIs written in C#. I assume you are not referring to .NET Core, so I am advising you by using .NET 4.8 Web API in my sample solution. I did not use any .NET Core functionality.

    I understand that your synchronous function you've written is to run the function LogicA synchronously, then run LogicB without waiting, and then return an Ok response to the browser. I am assuming LogicB is not resource-intensive or in need of being broken into parallel processes. I am also assuming LogicB will in some way, shape, or form perform any action required in your application until a later process, which you've not provided and I cannot address without more details.

    Please see my Proof-of-Concept with in-line comments to describe the logic as best I can. Please let me know if you have additional questions.

            /// <summary>
            /// Initial code provided by user asking question
            /// </summary>
            /// <param name="request">Object used in Proof-of-Concept</param>
            /// <returns>An ActionResult object</returns>
            public IActionResult MyWebApiMethod(HttpRequest request)
            {
                // Let's see what thread we're running on just for fun
                GetCurrentThread();
    
                // synchronous proof-of-concept
                LogicA(request);
    
                // asynchronous proof-of-concept - runs in new thread, thus not blocking this one
                // refer to https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming for some best-practices
                Task.Run(() => LogicB(request));
                Console.WriteLine("I'm gonna go return OK to my caller now! The rest is up to you to handle, young padawan. :)");
                GetCurrentThread();
    
                // code from original question
               return Ok(request);
            }
    
            private static void GetCurrentThread()
            {
                Console.WriteLine(Thread.CurrentThread);
            }
    
            private async Task LogicB(HttpRequest request)
            {
                Console.WriteLine("Begin Logic B");
                GetCurrentThread();
                await Task.Delay(10000);
                Console.WriteLine(request.Url);
                Console.WriteLine("End Logic B");
            }
    
            /// <summary>
            /// Demonstration of a syncronous function
            /// </summary>
            /// <param name="request">The object to perform actions on</param>
            private void LogicA(HttpRequest request)
            {
                Console.WriteLine("Begin Logic A");
                GetCurrentThread();
                Thread.Sleep(2500);
                Console.WriteLine(request.Url);
                Console.WriteLine("End Logic A");
            }
    
    0 comments No comments

  3. greably 0 Reputation points
    2023-03-31T14:17:35.3866667+00:00

    To achieve non-blocking processing in a Web API method, you can use asynchronous programming with the async and await keywords. This allows the application to perform other tasks while waiting for a response from a long-running operation.

    Here's an example of how to implement non-blocking processing in a Web API method:

    1. Declare the Web API method with the async keyword to indicate that it is an asynchronous method.
    2. Use the await keyword to call any long-running operations, such as database queries or external API requests.
    3. Return a Task or Task<T> object instead of a concrete type to indicate that the method is asynchronous.
    4. Configure the Web API to use the Task-based Asynchronous Pattern (TAP) by setting the Task<TResult> return type of the method.

    Here's an example of a Web API method that implements non-blocking processing using asynchronous programming:

    [HttpGet]
    public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
    {
        // Call a long-running operation asynchronously using the await keyword
        var products = await _productService.GetAllProductsAsync();
    
        // Return a Task object to indicate that the method is asynchronous
        return Ok(products);
    }
    
    0 comments No comments

  4. Lex Li (Microsoft) 4,327 Reputation points Microsoft Employee
    2023-04-02T04:57:47.8733333+00:00

    The discussion is meaningless if you don't reveal how long LogicA and LogicB take to finish.

    As a typical Web API framework, ASP.NET Core Web API assumes every call to finish as quickly as possible (no matter you write it in async or sync approach). So if the methods take several seconds to finish, converting to async/await won't give you much benefit. Threading/message queues are not helpful either, as the typical web service call timeout will kill all the efforts.

    A possible and commonly used approach is to switch to a framework like SignalR, where clients subscribe to realtime message/notification hubs on the server side. Then no matter how long an operation is, the hub can push the notifications down to the clients,

    https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-7.0