Распространение OperationContext в асинхронный вызов WCF
С C#5 Async-Await в WCF, после ожидания, если остальная часть кода продолжается в другом потоке, мы теряем текущий контекст операции. (Operation Context.Current равен нулю).
Я работаю над службой 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>
где " MyBindingExtention" получает доступ к тексту операции для получения некоторой информации.
public async Task<string> GetExternalData(int value)
{
var oc = OperationContext.Current;
//External Web service Call
var response = await externalService.GetDataAsync();
return response.text;
}
Есть ли хороший способ заставить Operation Context распространяться во внешний вызов службы, а затем снова в выполнение оставшегося кода?
1 ответ
Вы можете использовать пользовательский контекст синхронизации. Вот образец 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);
}