Распространение 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);
}
Другие вопросы по тегам