在WCF服务中使用async/await时,在第一次等待之后,OperationContext.Current为null

mdo*_*tas 35 .net wcf async-await .net-4.5

我在.NET 4.5中使用async/await模式在WCF中实现一些服务方法.示例服务:

合同:

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

执行:

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

        await Task.Delay(10);

        context = OperationContext.Current; // context is null
    }
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,在第一次await OperationContext.Current返回后null我无法访问OperationContext.Current.IncomingMessageHeaders.

在这个简单的例子中,这不是问题,因为我可以在之前捕获上下文await.但是在现实世界OperationContext.Current中,正在从调用堆栈内部访问,我真的不想更改大量代码只是为了进一步传递上下文.

有没有办法在await点之后获取操作上下文而不是手动将其传递给堆栈?

Jon*_*ole 28

遗憾的是,这不起作用,我们将在未来的版本中看到修复.

同时,有一种方法可以将上下文重新应用于当前线程,这样您就不必传递对象:

    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;
    }  
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,DoSomethingElse()方法将按预期访问OperationContext.Current.

  • 乔恩 - 你清楚地知道的人数超过大多数16人(我在MSDN上发现了你的博客).我建议您更新您的个人资料,以便人们了解您的答案质量. (5认同)
  • 使用OperationContextScope的主要原因是将OperationContext.Current设置为传递给构造函数的操作.这可以防止您必须将ctx实例传递给深度调用堆栈(例如,您不必修改方法签名以获取OperationContext参数). (2认同)
  • 此解决方案不允许从await中访问OperationContext.Current.在上面的例子中,是的,它有效. (2认同)

Ste*_*ary 21

我认为你最好的选择是实际捕获它并手动传递它.您可能会发现这会提高代码的可测试性.

也就是说,还有其他几种选择:

  1. 把它添加到LogicalCallContext.
  2. 安装你自己的SynchronizationContext,OperationContext.Current当它做的时候设置Post; 这就是ASP.NET保留它的方式HttpContext.Current.
  3. 安装你自己的TaskScheduler套装OperationContext.Current.

您可能还想在Microsoft Connect上引发此问题.


Dix*_*onD 7

它似乎在.Net 4.6.2中得到修复.看公告