我正在使用客户端库来访问第 3 方 API。该库由 NSwagStudio 从 Swagger 文档生成。
我正在开发的应用程序在其所有调用中都是完全同步的,并且将其更新为异步超出了我正在开发的范围。
当我从单元测试中测试客户端库时,它工作正常。当我尝试从 ASP.Net 应用程序中调用它时,我收到以下错误:
CancellationTokenSource 已被释放。
我已经将客户端库提炼为演示问题的要点,我选择了一个选项来提供同步方法和异步:
public class ClientApi
{
private readonly HttpClient _httpClient;
public ClientApi(HttpClient httpClient)
{
_httpClient = httpClient;
}
public string BaseUrl { get; set; }
public object Get()
{
return Task.Run(async () => await GetAsync(CancellationToken.None)).GetAwaiter().GetResult();
}
/// <returns>OK</returns>
/// <param name="cancellationToken">
/// A cancellation token that can be used by other objects or threads to receive notice of
/// cancellation.
/// </param>
public async Task<string> GetAsync(CancellationToken cancellationToken)
{
var client_ = _httpClient;
try
{
using (var request_ = new HttpRequestMessage())
{
request_.Method = new HttpMethod("GET");
request_.RequestUri = new System.Uri(BaseUrl, System.UriKind.RelativeOrAbsolute);
var response_ = await client_.SendAsync(
request_,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken
).ConfigureAwait(false);
try
{
// Exception occurs on following line
var responseData_ = response_.Content == null
? null
: await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
return responseData_;
}
finally
{
response_?.Dispose();
}
}
}
finally { }
}
}
这是调用它的代码:
protected void OnClick(object sender, EventArgs e)
{
var httpClient = new HttpClient();
var client = new ClientApi(httpClient)
{
BaseUrl = "https://www.google.com"
};
var html = client.Get();
}
调用它的代码只是一个带有按钮的 asp.net 页面,并且按钮事件运行与通过的单元测试相同的代码。
当我在调试器中比较运行时:从单元测试中,response_.Content 对象没有取消令牌,但是当从 asp.net 运行时它有。事实上,它们几乎看起来是不同的对象,尽管 GetType() 将它们都报告为 System.Net.Http.StreamContent。从反编译类,这没有 _cancellationtoken 属性,那么调试器从哪里得到它?
我猜对我的asp.net web 应用程序的http 请求有它自己的令牌和源,它以某种方式被HttpClient 使用。但是,客户端正在等待所有异步调用以同步获取结果,所以我不明白如何处理底层 CTS,因为我们还没有从客户端库的调用中返回。
任何人都可以理解发生了什么并且有解决方案吗?