Асинхронные вызовы клиента WCF с пользовательскими заголовками: этот OperationContextScope удаляется из строя


Я вызываю службу WCF из приложения WinRT. Служба требует, чтобы некоторые заголовки были установлены для проверки подлинности. Проблема в том, что если я делаю несколько вызовов к службе одновременно, я получаю следующее исключение:

Этот OperationContextScope выбывает из строя.

Текущий код выглядит следующим образом:

public async Task<Result> CallServerAsync()
{
    var address = new EndpointAddress(url);
    var client = new AdminServiceClient(endpointConfig, address);

    using (new OperationContextScope(client.InnerChannel))
    {
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = GetHeader();

        var request = new MyRequest(...); 
        {
            context = context,
        };

        var result = await client.GetDataFromServerAsync(request);
    }
}

Я нашел следующий комментарий из docs :

Не используйте асинхронный шаблон "ожидания" в блоке OperationContextScope. Когда продолжение происходит, оно может выполняться в другом потоке, и OperationContextScope является потоко-специфичным. Если вам нужно вызвать "await" для асинхронного вызова, используйте его вне блока OperationContextScope.

Так что, похоже, я явно неправильно вызываю службу. Но каков же правильный путь?

2 14

2 ответа:

Все, кажется, работает довольно хорошо со следующим кодом:

public async void TestMethod()
{
    var result = await CallServerAsync();
}

public Task<Result> CallServerAsync()
{
    var address = new EndpointAddress(url);
    var client = new AdminServiceClient(endpointConfig, address);

    using (new OperationContextScope(client.InnerChannel))
    {
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = GetHeader();

        var request = new MyRequest(...); 
        {
            context = context,
        };

        return client.GetDataFromServerAsync(request);
    }
}

Это известная "проблема", и для тех, кто застрял с этим, вы можете просто запустить вызов синхронно. Используйте GetAwaiter ().GetResult (); вместо этого, поскольку он вообще не планирует задачу, он просто блокирует вызывающий поток, пока задача не будет завершена.

public Result CallServer()
{
    var address = new EndpointAddress(url);
    var client = new AdminServiceClient(endpointConfig, address);

    using (new OperationContextScope(client.InnerChannel))
    {
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = GetHeader();

        var request = new MyRequest(...); 
        {
            context = context,
        };

        return client.GetDataFromServerAsync(request).GetAwaiter().GetResult();
    }
}