【问题标题】:How do I wrap a Web Api's async call and results as a synchronous method?如何将 Web Api 异步调用和结果包装为同步方法?
【发布时间】:2014-04-25 09:56:29
【问题描述】:

我需要将第三方的 Web API 方法集成到 WCF 服务中。 WCF 服务将被另一个外部方调用,他们希望调用和返回是同步的。

我可以使用通常的RestClient.ExecuteAsync 从 API 获取结果。

我为同步调用整理了以下内容:

public static List<Books> GetSyncBooks(int companyId)
{
    var response = GetSynchronousBooks(companyId);  
    var content = response.Result.Content;
    List<Books> result = new List<Books>();

    return Helpers.JSONSerialiser.Deserialize<BookList>(content);
}


async private static Task<IRestResponse> GetSynchronousBooks(int companyId)
{
    var request = BuildGETRequest("Book", companyId);
    var response = await RestSharpHelper.ExecuteSynchronousRequest(request);

    return response;
}

public static Task<IRestResponse> ExecuteSynchronousRequest(RestRequest request)
{
    var client = new RestClient(BaseUrl);
    client.AddHandler("application/json", new RestSharpJsonDotNetDeserializers());

    var tcs = new TaskCompletionSource<IRestResponse>(TaskCreationOptions.AttachedToParent);

    client.ExecuteAsync(request, (restResponse, asyncHandle) =>
    {                
        if (restResponse.ResponseStatus == ResponseStatus.Error)
            tcs.SetException(restResponse.ErrorException);
        else
            tcs.SetResult(restResponse);
    });
    return tcs.Task;
// BREAKPOINT here shows TASK value as
//  Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
}

然而,问题是我从来没有使用这个得到结果。响应内容始终为空。我做错了什么?

编辑:谢谢斯蒂芬。我在这个主题的一些问题上看到了你的名字:你的分数似乎表明你知道如何解决这个问题。根据您在另一个问题上的回答,我确实实现了 wcf 服务调用。我可以问你一个相关的后续问题吗?像这个例子这样的异步 WCF 服务调用的可扩展性如何?对于每秒 10 到 100 个范围内的多个同时调用,它会“正常工作”,而忽略下游的处理开销吗?

【问题讨论】:

    标签: c# wcf asp.net-web-api restsharp


    【解决方案1】:

    我假设您的 WCF 服务托管在 ASP.NET 中。

    您的问题在这里:response.Result。我在我的博客上解释了this deadlock situation。总之,await 将捕获当前“上下文”(在本例中为 ASP.NET 请求上下文)并将使用它来恢复 async 方法。但是,ASP.NET 请求上下文一次只允许一个线程,因此如果请求线程被阻塞(调用response.Result),那么async 方法将永远无法继续,并且会出现死锁。

    解决方法是纠正这个误解:

    WCF 服务将被另一个外部方调用,他们希望调用和返回是同步的。

    由于您处理的是客户端/服务器方案,因此您不必使其同步。客户端的异步完全独立于服务器的异步。

    所以,只需异步实现您的 WCF 服务:

    public static Task<List<Books>> GetBooksAsync(int companyId)
    {
      var response = await GetBooksAsync(companyId);  
      var content = response.Content;
      List<Books> result = new List<Books>();
    
      return Helpers.JSONSerialiser.Deserialize<BookList>(content);
    }
    

    如果客户愿意,他们仍然可以同步调用它。

    【讨论】:

    • 谢谢斯蒂芬。我在这个主题的一些问题上看到了你的名字:你的分数似乎表明你知道如何解决这个问题。根据您对另一个问题的回答,我确实实现了 wcf 服务调用。我可以问你一个相关的后续问题吗?像这个例子这样的异步 WCF 服务调用的可扩展性如何?对于每秒 10 到 100 个范围内的多个同时调用,它会“正常工作”,而忽略下游的处理开销吗?
    • 当然。使用基于 I/O 的异步实现,即使它仅在基本硬件上运行,您也应该能够处理数千个同时调用。请注意,可能需要更改 ASP.NET 会话状态和 WCF 服务并发设置以允许同时调用。
    猜你喜欢
    • 2016-06-21
    • 2020-03-10
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 2014-02-19
    • 2011-10-14
    相关资源
    最近更新 更多