如何包装Web Api';s异步调用,并将结果作为同步方法
本文关键字:调用 异步 结果 同步方法 包装 何包装 Web Api | 更新日期: 2023-09-27 17:59:57
我需要将第三方的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}"
}
然而,问题是,我从来没有得到一个结果使用这个。响应内容始终为null。我做错了什么?
编辑:谢谢斯蒂芬。我在这里的一些问题上看到了你的名字:你的分数似乎表明你知道如何解决这个问题。根据您对另一个问题的回答,我确实实现了您所说的wcf服务调用。我可以问你一个相关的后续问题吗?像本例这样的异步WCF服务调用的可扩展性如何?它会"只适用于"每秒10到100次的多个同时调用,而忽略下游的处理开销吗?
我假设您的WCF服务托管在ASP.NET中。
您的问题在这里:response.Result
。我在博客上解释了这种僵局的情况。总之,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);
}
如果客户愿意,他们仍然可以同步调用它。