WCF
async programming
asynchronous methods
.NET
C#

await async WCF method

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

You can absolutely await WCF calls, but the exact shape depends on what the generated client proxy exposes. In modern usage, the cleanest case is a service reference or client proxy that already returns Task or Task<T>. If the proxy still exposes older Begin and End methods, you can wrap them into a task before awaiting.

Await a Task-Based WCF Client Method

If your generated WCF client already exposes async methods, use them directly.

csharp
1using System;
2using System.Threading.Tasks;
3
4public async Task<string> LoadMessageAsync()
5{
6    var client = new MyServiceClient();
7
8    try
9    {
10        string result = await client.GetMessageAsync();
11        return result;
12    }
13    finally
14    {
15        if (client.State == System.ServiceModel.CommunicationState.Faulted)
16            client.Abort();
17        else
18            client.Close();
19    }
20}

That is the ideal client-side pattern because the method is already task-based and fits naturally with await.

Wrap Older Begin and End Methods

Some WCF clients still use the older asynchronous pattern with BeginXxx and EndXxx. In that case, convert the pair into a task.

csharp
1using System;
2using System.Threading.Tasks;
3
4public Task<string> GetMessageWrappedAsync(MyServiceClient client)
5{
6    return Task.Factory.FromAsync(
7        client.BeginGetMessage,
8        client.EndGetMessage,
9        null
10    );
11}

Then await it:

csharp
1public async Task<string> LoadMessageAsync()
2{
3    var client = new MyServiceClient();
4    try
5    {
6        return await GetMessageWrappedAsync(client);
7    }
8    finally
9    {
10        if (client.State == System.ServiceModel.CommunicationState.Faulted)
11            client.Abort();
12        else
13            client.Close();
14    }
15}

This gives you an async-friendly API even when the generated proxy is older.

Do Not Block on Async WCF Calls

Avoid .Result and .Wait() on WCF tasks when writing UI or server code. Blocking on async calls can reduce scalability and, in some environments, contribute to deadlocks or poor responsiveness.

The whole point of using await is to keep the code non-blocking and readable:

csharp
string message = await client.GetMessageAsync();

That is almost always preferable to:

csharp
string message = client.GetMessageAsync().Result;

Think About the Service Side Too

Awaiting the client call is one part of the picture. On the service side, if the implementation does I/O-bound work, it can also use task-based async methods.

csharp
1[ServiceContract]
2public interface IMessageService
3{
4    [OperationContract]
5    Task<string> GetMessageAsync();
6}

And the implementation:

csharp
1public class MessageService : IMessageService
2{
3    public async Task<string> GetMessageAsync()
4    {
5        await Task.Delay(100);
6        return "hello";
7    }
8}

That keeps the full request path aligned with asynchronous programming rather than mixing async on one side with unnecessary blocking on the other.

Generate the Right Client Shape

Whether you can await directly often depends on how the proxy was generated. Some service-reference tools can generate task-based operations automatically, while older code generation paths may still give you only synchronous methods or Begin and End pairs. If the proxy shape looks outdated, regenerate it with task-based async support before writing wrappers by hand.

That usually leads to cleaner application code than maintaining custom wrappers around every service call forever.

Common Pitfalls

  • Calling .Result or .Wait() on a WCF task instead of awaiting it.
  • Forgetting to close or abort the WCF client correctly after the awaited call.
  • Assuming old Begin and End patterns can be awaited directly without wrapping.
  • Making the client async while the service implementation still blocks on long I/O.
  • Ignoring faulted client state and calling Close() where Abort() is required.

Summary

  • Task-based WCF proxy methods can be awaited directly.
  • Older Begin and End proxy methods can be wrapped with Task.Factory.FromAsync.
  • Use await instead of blocking with .Result or .Wait().
  • Clean up WCF clients carefully, especially when faults occur.
  • Async works best when both client and service paths avoid unnecessary blocking.

Course illustration
Course illustration

All Rights Reserved.