Asynchronous programming
.NET Core Asynchronous C# Patterns Visual Studio

How to use the Async and Await Pattern in .NET Core Applications

Welcome to today’s post.

In today’s post I will discuss using the basic asynchronous programming patterns in .NET Core Applications.

The reason behind using the asynchronous pattern is to ensure that some code blocks that use non-thread-safe resources such as database tables or physical files are protected from multiple concurrent threads. Should a thread access a resource that is already being accessed by another thread, the well-known access violation… error will appear.

The await keyword precedes the resource or method call that we wish to protect from simultaneous access. Once the thread has completed the call to the resource, it releases the lock to the resource and allows any waiting thread to access the resource.

The await keyword must be present in a method that is declared with the async keyword.

I will show examples of how these are used in the first section.

Applying the Async and Await Patterns in .NET Core Methods

First, I will look at the basic pattern for declaring an asynchronous method in C#.

To declare an asynchronous method, we need to declare the namespace:

using System.Threading.Tasks;

The basic asynchronous method is declared as follows:

public async Task AsyncMethod()
{ 
   // do something.
   ..
   await AnotherAsyncMethod();
}

In fact, since C# v5.0, with typical Web API controllers, the standard practice is to implement controllers with the async pattern. An example is shown below:

[HttpPost("api/[controller]/Create")]
public async Task<ActionResult> Create([FromBody] 
  BookViewModel model)
{
   try
   {
      .. does something
      BookViewModel book = ...
      await _bookService.SaveBook(book);
      return Ok(book); 
   }
   catch (Exception ex)
   {
      _logger.LogError(ex.Message);
      return BadRequest("Cannot create book record.");
   }
}

The reason for using this common asynchronous pattern is that HTTP web API requests are all asynchronous. If the call chain contains one synchronous call, then there is a likelihood of deadlocked context.

We will look at some examples in the next section.

Examples of Asynchronous Methods

In this section, I will cover some examples of the different types of asynchronous methods.

The simplest is the one without any return value. It is equivalent to a void return asynchronous method.

An example is shown below from a service class:

public async Task SaveBook(BookViewModel vm)
{ 
   _db.Add(vm);
   await _db.SaveChangesAsync();
}

For asynchronous calls to data contexts to be successful, the DbContext lifetime must be scoped within the web API request. With a transient lifetime, the transaction will fail.

To call this method, use the following pattern:

BookViewModel book = new BookViewModel()
{
   // assign object properties
}
await _bookService.SaveBook(book);

The next type of asynchronous method returns an instance object.

An example is shown below from a service class:

public async Task<BookViewModel> GetBook(int id)
{
   BookLoan.Models.BookViewModel book = 
await _db.Books.Where(m => m.ID == id).SingleOrDefaultAsync();
   if (book != null)
      return book;
   return null;
}

To call this method, use the following pattern:

BookViewModel bvm = new BookViewModel();
bvm = await _bookService.GetBook(id);

The next type of asynchronous method returns a list of an instance object.

An example is shown below from a service class:

public async Task<List<BookViewModel>> GetBooks()
{
   return await _db.Books.ToListAsync();
}

The above will return asynchronously as the collection libraries are thread safe.

To call this method, use the following pattern:

IList<BookViewModel> book = new List<BookViewModel>();
   …
book = await _bookService.GetBooks(); 

Note: All methods from the following static class in Entity Framework Core that return a Task object:

Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions

are asynchronous methods that return a Task object or collection of Task objects.

For example:

public static Task<TSource> SingleOrDefaultAsync<TSource>(…);

Note: All methods from the following static class in Entity Framework Core that return a Task object:

Microsoft.EntityFrameworkCore.DbContext 

are asynchronous methods that return a Task object or collection of Task objects.

For example:

public virtual Task<int> SaveChangesAsync(
  CancellationToken cancellationToken = default(CancellationToken));

As I mentioned earlier, calls using Entity Framework Core libraries have threads scoped to the web request.

Calling Asynchronous Methods from Synchronous Methods

The other pattern I would like to explain is calling an asynchronous method from a synchronous method. An example of this is shown below:

public void Initialize(ApplicationDbContext context)
{
   var appOptions = new AppConfiguration();
   Configuration.GetSection("AppSettings").Bind(appOptions);
   SeedAccounts seed_acc = new SeedAccounts(context, appOptions);
   var task = Task.Run(async() => await 
      seed_acc.GenerateUserAccounts());
   var result = task.Wait(5000);
}

What this call does is to run the asynchronous call within a thread, then stores the results of the call within a Task object. The results of the task object return to the calling method after a short delay.

There is a case where you cannot use the async … await pattern because your method is declared synchronously and there are no asynchronous calls within your method.

In this case you can use the GetAwaiter().GetResult() which, after the asynchronous call to the target method, will block the return result synchronously:

Task<bool> isInMemberRoleAction = 
   _userRoleService.IsUserInRole(username, "Member");
bool isInMemberRole =   
   isInMemberRoleAction.GetAwaiter().GetResult();
if (isInMemberRole)
{
   …
}

Warning: Using GetResult() within a single-threaded context, such as a Windows application can deadlock the main UI thread.

Another context where this might be used is within an NUnit test that are run synchronously and may be calling asynchronous methods to determine test assertions.

For example:

var bookService = new BookService(context, null);
var books = bookService.GetBooks().GetAwaiter();
var result = books.GetResult();
Assert.AreEqual(3, result.Count);

The above overview has shown us how to make use of the async and await keywords to protect resources from multiple threads within a .NET Core application.

That’s all for this post.

I hope you found it useful and informative.

Social media & sharing icons powered by UltimatelySocial