Asynchronous operations

We could call it a muscle memory, as we could notice that an asynchronous operation is already in place; we perform all operations in an asynchronous way. Even though it's been covered, let's reiterate how the asynchronous operations were handled in our blogging system and see the simplicity when we used async/await syntactic sugar implementations for asynchronous operations.

The asynchronous execution helps us in supporting multiple requests in parallel, without locking a thread against a long-running process. To understand how the threads should be managed properly, let's go through the following execution process:

  • The request reaching the ASP.NET pipeline will be allocated to a thread, which takes care of the execution
  • The thread will be occupied until the request is complete
  • If the action consumes any long-running process in a synchronous way, then the thread will be blocked until the process execution is complete. If all the threads in the thread pool is occupied, then it cannot serve additional requests
  • If the long-running process is implemented in an asynchronous way, then once the action is triggered, the thread will be released back to the thread pool, the released thread would be allocated to new request
  • Once the long-running process is complete, a new thread will be allocated to complete the request execution

Since we already have an asynchronous implementation in place, we will start examining them right from the controller up to the data context execution. Let's take a look at the post controller Index action that is decorated with the async keyword, which also requires a return type to be wrapped inside the Task<> generic type. The asynchronous method should be invoked using the await keyword as shown in the following code:

    public async Task<IActionResult> Index()
{
var posts = await _postRepository.GetAsync(
new GetAllPostsQuery(_context)
{
IncludeData = true
});
// Code removed for brevity
}

Let's dig in deep and investigate how this GetAsync() is implemented. It is a generic implementation that invokes HandleAsync() using the async/await keywords as shown here:

    public async Task<IEnumerable<Post>> GetAsync<T>(T query)
where T : IQueryHandlerAsync<IEnumerable<Post>>
{
return await query.HandleAsync();
}

The HandleAsync() method is again implemented inside GetAllPostsQuery (in our scenario), which consumes the EF Core asynchronous ToListAsync() method, which wraps up our asynchronous implementation. This ensures that the database execution happens in an asynchronous way, and the operation continues after the data is returned from the data store. The following code performs asynchronous executions on ToListAsync() methods which will perform database operation:

    public class GetAllPostsQuery : QueryBase, 
IGetAllPostsQuery<GetAllPostsQuery>
{
// Code removed for brevity
public async Task<IEnumerable<Post>> HandleAsync()
{
var posts = IncludeData
? await Context.Posts
.Include(p => p.Author).Include(p => p.Blog)
.Include(p => p.Category).Include(p=>p.TagPosts)
.ToListAsync()
: await Context.Posts
.ToListAsync();
// Code removed for brevity
}
}

We have explored how asynchronous operations are implemented consuming EF Core async methods. In the next section, let's move on a little further and see how transactions are leveraged.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset