将OperationContext传播到异步WCF调用中



使用WCF中的C#5异步Await,在等待之后,如果其余代码在不同的线程上继续,我们将释放当前操作上下文。(OperationContext.Current为null)。

我正在开发一个WCF服务,它调用另一个外部服务。在访问操作上下文的外部服务调用中使用了一些自定义绑定扩展。因此,我需要在这个调用期间传播上下文,它不能只将操作上下文复制到本地变量中。

我的配置看起来像这个

<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyCustomBinding">
<MyBindingExtention/>
<security authenticationMode="UserNameOverTransport" />
<textMessageEncoding maxReadPoolSize="64" >
<readerQuotas maxStringContentLength="8192" />
</textMessageEncoding>
<httpsTransport manualAddressing="false" maxReceivedMessageSize="65536" />
</binding>
</customBinding>
<client>
<endpoint address="https://ExternalService.svc" binding="customBinding" bindingConfiguration="MyCustomBinding" contract="Contract" name="ExternalService"/>
</client>
</bindings> 
<extensions>
<bindingElementExtensions>
<add name="MyBindingExtention" type="Bindings.MyBindingExtention, Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bindingElementExtensions>  
</extensions>   
</system.serviceModel>

其中">MyBindingExtetion">访问操作上下文以获取一些信息。

public async Task<string> GetExternalData(int value)
{
var oc = OperationContext.Current;
//External Web service Call
var response = await externalService.GetDataAsync();
return response.text;
}

有没有一种好的方法可以让OperationContext传播到外部服务调用中,然后再次传播到剩余的代码执行中?

您可以使用自定义同步上下文。下面是一个示例SynchronizationContext实现:

public class OperationContextSynchronizationContext : SynchronizationContext
{
private readonly OperationContext context;
public OperationContextSynchronizationContext(IClientChannel channel) : this(new OperationContext(channel)) { }
public OperationContextSynchronizationContext(OperationContext context)
{
OperationContext.Current = context;
this.context = context;
}
public override void Post(SendOrPostCallback d, object state)
{
OperationContext.Current = context;
d(state);
}
}

用途:

var currentSynchronizationContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(new OperationContextSynchronizationContext(client.InnerChannel));
var response = await client.RequestAsync();
// safe to use OperationContext.Current here
}
finally
{
SynchronizationContext.SetSynchronizationContext(currentSynchronizationContext);
}

最新更新