ASP.NET web API - System.Threading.Tasks.TaskCanceledException: 一个任务被取消的困境

ASP.NET web API - System.Threading.Tasks.TaskCanceledException: A task was canceled dilemma

我有一个 asp.net 网站 API。 (net framework 4.6.1) 我在我的一项操作中调用了第三方 rest API (Product)。在功能测试中,一切都按预期工作,没问题。但是当我进行尖峰测试时(比方说,100 个用户,10 秒的启动时间),在一些成功的响应之后我得到 System.Threading.Tasks.TaskCanceledException: A task was canceled error。我用谷歌搜索并发现这可能是由于超时。我添加了 TimeSpan.FromSeconds(600); 但仍然出现相同的错误。

我是这样称呼这个第 3 方的 API。异步调用有什么问题吗?你能看看我的代码吗?

public class UtilitiesTest
    {
        private static readonly HttpClient _httpClient = new HttpClient();


       //some not relevant code here

        public static async Task<HttpResponseMessage> CallRazer(GameRequest gameRequest, string url)
        {
            try
            {
                FormUrlEncodedContent content = null;

                if (url == "Product/")
                {
                    try
                    {
                        //some code here


                        //Timeout
                        _httpClient.Timeout = TimeSpan.FromSeconds(600);
                        //Call Game
                        var response = await _httpClient.PostAsync("https://test.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
                else
                {
                    try
                    {
                        //some code here

                        //Call Game
                        var response = await _httpClient.PostAsync("https://test.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }


    }

我是这样称呼 Razer 的:

private async Task<HttpResponseMessage> CallProducts()
        {
            //some code here

            #region Call Razer for products


            //**Call Razer**
            var response = await Utilities.CallRazer(products, "Product/");

            var htmlResponse = await response.Content.ReadAsStringAsync();
            var model = JsonConvert.DeserializeObject<ProductResponseDto>(htmlResponse);

           // some code here

            return response;
        }

另一个论坛有人建议我使用 HTTPWeb Request 而不是 Httpclient。所以我像下面这样更改了我的代码,所有的麻烦都消失了。

//HTTPWebRequest
var request = (HttpWebRequest) WebRequest.Create("http://test.com" + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";

var keyValueContent = productRequest.ToKeyValue();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();

using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
     streamWriter.Write(urlEncodedString);
}

HttpWebResponse httpResponse = (HttpWebResponse) (await request.GetResponseAsync());

response = new HttpResponseMessage
{
     StatusCode = httpResponse.StatusCode,
     Content = new StreamContent(httpResponse.GetResponseStream()),
};

return response;

如果它在 600 秒后仍然超时,那么您的网络服务就跟不上了。

但是,是的,超时会产生一个TaskCanceledException,这一点都不直观。这实际上至少在 .NET Core 中会发生变化 (just fixed last week),但这对您没有帮助。

这是我用来重新抛出 TimeoutException 的代码。 other 可能抛出 TaskCanceledException 的唯一原因是,如果您通过了最终被取消的 CancellationToken,但您没有。所以肯定超时了。

} catch (TaskCanceledException) {
    //Could have been caused by cancellation or timeout if you used one.
    //If that was the case, rethrow.
    //cancellationToken.ThrowIfCancellationRequested();

    //HttpClient throws TaskCanceledException when the request times out. That's dumb.
    //Throw TimeoutException instead and say how long we waited.
    string time;
    if (_httpClient.Timeout.TotalHours > 1) {
        time = $"{_httpClient.Timeout.TotalHours:N1} hours";
    } else if (_httpClient.Timeout.TotalMinutes > 1) {
        time = $"{_httpClient.Timeout.TotalMinutes:N1} minutes";
    } else if (_httpClient.Timeout.TotalSeconds > 1) {
        time = $"{_httpClient.Timeout.TotalSeconds:N1} seconds";
    } else {
        time = $"{_httpClient.Timeout.TotalMilliseconds:N0} milliseconds";
    }
    throw new TimeoutException($"No response after waiting {time}.");
}