Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OperationContext.Current is null after first await when using async/await in WCF service

I am using async/await pattern in .NET 4.5 to implement some service methods in WCF. Example service:

Contract:

[ServiceContract(Namespace = "http://async.test/")]
public interface IAsyncTest
{
    Task DoSomethingAsync();
}

Implementation:

MyAsyncService : IAsyncTest
{
    public async Task DoSomethingAsync()
    {
        var context = OperationContext.Current; // context is present

        await Task.Delay(10);

        context = OperationContext.Current; // context is null
    }
}

The problem I am having is that after first await OperationContext.Current returns null and I can't access OperationContext.Current.IncomingMessageHeaders.

In this simple example this is not a problem since I can capture the context before the await. But in the real world case OperationContext.Current is being accessed from deep inside the call stack and I really don't want to change lots of code just to pass the context further.

Is there a way to get operation context after await point without passing it down the stack manually?

like image 842
mdonatas Avatar asked Oct 09 '12 09:10

mdonatas


3 Answers

It is unfortunate that this doesn't work and we will see about getting a fix out in a future release.

In the mean time, there is a way to reapply the context to the current thread so that you don't have to pass the object around:

    public async Task<double> Add(double n1, double n2)
    {

        OperationContext ctx = OperationContext.Current;

        await Task.Delay(100);

        using (new OperationContextScope(ctx))
        {
            DoSomethingElse();
        }
        return n1 + n2;
    }  

In the above example, the DoSomethingElse() method will have access to OperationContext.Current as expected.

like image 109
JonCole Avatar answered Oct 03 '22 03:10

JonCole


I think your best option is to actually capture it and pass it manually. You may find this improves the testability of your code.

That said, there are a couple of other options:

  1. Add it to the LogicalCallContext.
  2. Install your own SynchronizationContext which will set OperationContext.Current when it does a Post; this is how ASP.NET preserves its HttpContext.Current.
  3. Install your own TaskScheduler which sets OperationContext.Current.

You may also want to raise this issue on Microsoft Connect.

like image 40
Stephen Cleary Avatar answered Oct 03 '22 02:10

Stephen Cleary


It seems to be fixed in .Net 4.6.2. See the announcement

like image 29
DixonD Avatar answered Oct 03 '22 04:10

DixonD