【问题标题】:Async WCF client calls with custom headers: This OperationContextScope is being disposed out of order带有自定义标头的异步 WCF 客户端调用:此 OperationContextScope 被乱序处理
【发布时间】:2012-10-22 19:15:06
【问题描述】:

我正在从 WinRT 应用程序调用 WCF 服务。该服务要求为身份验证设置一些标头。问题是,如果我同时对服务进行多次调用,我会得到以下异常:

此 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);
    }
}

我发现以下评论from the docs

不要在 OperationContextScope 块中使用异步“等待”模式。当继续发生时,它可能在不同的线程上运行,并且 OperationContextScope 是特定于线程的。如果您需要为异步调用调用“等待”,请在 OperationContextScope 块之外使用它。

所以看来我显然错误地调用了该服务。但是正确的方法是什么?

【问题讨论】:

    标签: c# wcf asynchronous wcf-client


    【解决方案1】:

    Microsoft documentation

    不要在 OperationContextScope 块中使用异步“等待”模式。当继续发生时,它可能在不同的线程上运行,并且 OperationContextScope 是特定于线程的。如果您需要为异步调用调用“等待”,请在 OperationContextScope 块之外使用它。

    所以最简单的正确解决方案是:

    Task<ResponseType> task;
    using (new OperationContextScope(client.InnerChannel))
    {
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = GetHeader();
    
        var request = new MyRequest(...); 
        {
            context = context,
        };
    
        task = client.GetDataFromServerAsync(request);
    }
    
    var result = await task;
    

    【讨论】:

    • 这似乎按预期工作。
    【解决方案2】:

    这是一个已知的“问题”,对于遇到此问题的任何人,您都可以简单地同步运行您的调用。使用 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();
        }
    }
    

    【讨论】:

      【解决方案3】:

      以下代码似乎一切正常:

      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);
          }
      }
      

      【讨论】:

      • 这可能会起作用,但它会巧合。因为您不等待 GetDataFromServerAsync 调用,所以不会发生线程切换。在调用实际完成之前,操作的上下文范围已经被释放。它起作用的原因可能是因为在内部调用等待内部之前添加了传出标头。
      • 您可以等待 GetDataFromServerAsync 在 using 块结束后立即返回的任务(将任务分配给变量)。
      • @sich 但在这种情况下,客户端不使用自定义消息属性。
      • @supertopi 为什么不呢,你在 using 块中启动操作,所有配置都被捕获,然后只等待它之外的完成。
      猜你喜欢
      • 2020-10-08
      • 2013-03-10
      • 2012-10-03
      • 2011-04-07
      • 1970-01-01
      • 2016-04-24
      • 1970-01-01
      • 2014-03-02
      • 2012-11-21
      相关资源
      最近更新 更多