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

时间:2019-08-21 08:24:37

标签: c# asp.net-web-api async-await dotnet-httpclient

我有一个asp.net Web API。 (净框架4.6.1)我正在其中一项操作中调用第三方rest API(产品)。在功能测试中,一切正常,没有问题。但是,当我执行尖峰测试(假设有100位用户,10秒的启动时间)时,经过一些成功的响应,我得到了System.Threading.Tasks.TaskCanceledException: A task was canceled error。我用谷歌搜索发现可能是由于超时。我添加了TimeSpan.FromSeconds(600);,但仍然遇到相同的错误。

这就是我所谓的第三方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;

1 个答案:

答案 0 :(得分:0)

如果600秒后仍然超时,则您的Web服务就跟不上。

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

这是我用来重新抛出TimeoutException的代码。可能引发TaskCanceledException的唯一 other 原因是,如果您通过了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}.");
}