Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

WCF Sync to Async Conversion

5.00/5 (1 vote)
15 Jan 2019CPOL3 min read 9.8K  
Converting a synchronous WCF contract to an asynchronous one

Introduction

This article presents some ideas on how to transition an existing working WCF contract to Async incrementally so that functionality is easily tested along the way and the contract can go live at any stage.

The ideas presented here are not original and are based on searching the net. There is no one author that I can thank but I would like to express my appreciation to all those developers out there who take the time to share their knowledge.

The problem I faced was a working WCF IIS hosted service. The contracts were all synchronous. They involve some Database activity and also call out to another 3rd party service. I wanted to wring as much performance out of the contracts as possible.

From general reading, it seemed Async programming would produce gains (mainly in the IIS server not wasting threads). I want to be clear that I am a learner with async and this is a chronicle of my 'voyage of discovery'. Hopefully, the experts out there will not find too much to disagree with.

A number of things had to be addressed.

  • alter the contract to Async without breaking the interface
  • convert a sync method to async
  • call an async method from a sync method

Note: .NET Framework 4.6.1 or higher is needed to make use of the async and await keywords.

Let's tackle these points in order.

Making Contract Async

Change the return type T (if any) of the interface contract declaration to Task<T>. Do the same to the implementing code and add the async keyword to the implementing code declaration.

Interface

C#
[OperationContract]
        [WebInvoke(
            Method = "POST",
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        Task<TransList> ProcessRequests(TransList incoming);

Implementation

C#
public async Task<TransList> ProcessRequestsV2(TransList incoming)
        {
TransList response = new TransList;
DoSomeStuff;
return response;
}

Once the declarations are in place, the code should still compile and produce a compiler warning CS4014:

Warnings CS4014 and CS1998: These warnings will come and go as you move through your conversion. They provide pointers to where async has not been implemented. The code is still functional and your service will still work.

Converting Sync Method to Async

The method shown is from a DataBase helper class. It shows the use of the inbuilt .framework async methods to read from the database.

Original Sync Method

C#
public bool GetProcessAllowed(string user)
      {
          const string sSql = "proc_GetProcessAllowed";
          using (var conn = new SqlConnection(_msConn))
          {
              using (var cmd = new SqlCommand(sSql, conn))
              {
                  conn.Open();
                  cmd.CommandType = CommandType.StoredProcedure;
                  cmd.Parameters.AddWithValue("@user", user);
                  using (var r = cmd.ExecuteReader())
                  {
                      if (r.Read())
                      {
                         return r.GetBoolean(0);
                      }
                      throw new ApplicationException
                          ("Dt.GetProcessAllowed not able to access database.");
                  }
              }
          }
      }

async Modification

C#
public async Task<bool> GetProcessAllowed(string user)
{
    const string sSql = "proc_GetProcessAllowed";
    using (var conn = new SqlConnection(_msConn))
    {
        await conn.OpenAsync();
        using (var cmd = new SqlCommand(sSql, conn))
        {
            //conn.Open();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@user", user);
            using (var r = await cmd.ExecuteReaderAsync())
            {
                if (r.Read())
                {
                        return r.GetBoolean(0);
                }
                throw new ApplicationException
                  ("Dt.GetProcessAllowed not able to access database.");
            }
        }
    }
}

Calling the Async Method from a Sync Method

Just to be clear, the calling method is still synchronous. It has not had async added to its declaration and the return type is unchanged. The following snippet shows the original call to the synchronous version of the called method (commented out) and the new call to the async version.

Note the use of the Result property to get back to the original boolean variables.

C#
//bool getProcessAllowed = _db.GetProcessAllowed(credentials.UserId);
//bool writeProcessRunning = _db.WriteProcessRunning(credentials.UserId, true);
Task<bool> getProcessAllowedAsync = _db.GetProcessAllowed(credentials.UserId);
Task<bool> writeProcessRunningAsync = _db.WriteProcessRunning(credentials.UserId, true);
bool getProcessAllowed = getProcessAllowedAsync.Result;
bool writeProcessRunning =  writeProcessRunning.Result;             
if (getProcessAllowed && writeProcessRunning)
{Do some stuff}

Calling the Async Method from an Async Method

Here, the calling method has been converted to async. The async keyword has been added to its declaration and its return type is Task<T> so it can await the return from the called method.

The following snippet shows the original call to the synchronous version of method (commented out) and the new call to the async version.

Note the use of the await instead of Result property to get back to the original boolean variables.

C#
//bool getProcessAllowed = _db.GetProcessAllowed(credentials.UserId);
//bool writeProcessRunning = _db.WriteProcessRunning(credentials.UserId, true);
Task<bool> getProcessAllowedAsync = _db.GetProcessAllowed(credentials.UserId);
Task<bool> writeProcessRunningAsync = _db.WriteProcessRunning(credentials.UserId, true);
bool getProcessAllowed = await getProcessAllowedAsync;
bool writeProcessRunning = await writeProcessRunningAsync;              
if (getProcessAllowed && writeProcessRunning)
{Do some stuff}

Conclusion

The crux for me is understanding the relationships between sync and async methods shown above.

It took a while to appreciate that adding the async keyword to a method and changing its return value from T to Task<T> still allowed it to function synchronously.

As you move through implementing your changes, the compiler warnings provide a good guide that the section you are working on still needs more work.

I hope the above proves useful to someone.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)