gpt4 book ai didi

c# - 调用 httpClient.GetAsync() 时发送任何数据失败,有时会捕获 TaskCanceledException

转载 作者:行者123 更新时间:2023-12-04 09:35:52 25 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Update .NET web service to use TLS 1.2

(7 个回答)



Singleton httpclient vs creating new httpclient request

(5 个回答)


1年前关闭。




我开发了 C# .net 4.6.1 应用程序(这是 Windows Service Application )。在应用程序中,我使用 HttpClient 与我们的后端 API 进行通信。随着时间的推移,应用程序不会向我们的后端发送请求(TaskCanceledException 被捕获)。
这是此异常的堆栈跟踪

System.Threading.Tasks.TaskCanceledException · A task was cancelled.

System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
TestHttpClient+<GetRequestAsync>d__20.MoveNext()
这个问题解决了两个原因
  • 重启应用后
  • 当重复尝试相同的请求时

  • 我使用 Fiddler 调查了这个问题, 当异常发生并且在正常情况下
  • In normal mode fiddler shows 2 requests
  • 结果=200,协议(protocol)=HTTP,主机=隧道,Url=api.example.com:443

  • in SyntaxView tab: A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.


  • 结果 = 200,协议(protocol) = HTTPS,主机 = api.example.com,网址 =/test
  • In failed mode Fiddler shows only 1 requst
  • 结果=200,协议(protocol)=HTTP,主机=隧道,Url=api.example.com:443,

  • in SyntaxView tab: After the client received notice of theestablished CONNECT, it failed to send any data


    这是我们的代码片段。
    class Program
    {
    static void Main(string[] args)
    {
    // I Tried also without Task.Run() i.e. MyClass myClass = GetAsync().Result;
    MyClass myClass = Task.Run(() => GetAsync().Result).Result ;
    }

    private static async Task<MyClass> GetAsync()
    {
    // I Tried also without .ConfigureAwait(false)
    MyClassResponse myClassResponse = await TestHttpClient.GetMyClassResponse().ConfigureAwait(false);
    return MyClass.Create(myClassResponse);
    }
    }
    public static class TestHttpClient
    {
    private static HttpClient _httpClient;

    public static void Init()
    {
    ServicePointManager.SecurityProtocol |= (SecurityProtocolType.Ssl3 |
    SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 |
    SecurityProtocolType.Tls);
    ServicePointManager.DefaultConnectionLimit = 10;
    _httpClient = CreateHttpClient();
    }

    private static HttpClient CreateHttpClient()
    {
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token .....");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.Timeout = TimeSpan.FromMilliseconds(10000);
    return client;
    }

    public static async Task<MyClassResponse> GetMyClassResponse()
    {
    HttpResponseMessage response = await GetRequestAsync("https://api.example.com/test");
    return await ParseToMyClassResponse<MyClassResponse>(response);
    }

    private static async Task<HttpResponseMessage> GetRequestAsync(string url)
    {
    try
    {
    return await _httpClient.GetAsync(new Uri(url));
    }
    catch (TaskCanceledException)
    {
    return new HttpResponseMessage(HttpStatusCode.RequestTimeout);
    }
    }

    private static async Task<T> ParseToMyClassResponse<T>(HttpResponseMessage response) where T : MyClassResponse, new()
    {
    T myClassResponse;
    try
    {
    string content = await response.Content.ReadAsStringAsync();
    response.EnsureSuccessStatusCode();
    myClassResponse = JsonConvert.DeserializeObject<T>(content);
    }
    catch (Exception ex)
    {
    myClassResponse = new T();
    }

    response.Dispose();
    return myClassResponse;
    }
    }

    我究竟做错了什么?
    为什么 Fiddler显示 "After the client received notice of the established CONNECT, it failed to send any data"信息。

    最佳答案

  • 首先,替换这个

  • static void Main(string[] args)
    {
    // I Tried also without Task.Run() i.e. MyClass myClass = GetAsync().Result;
    MyClass myClass = Task.Run(() => GetAsync().Result).Result ;
    }
    与威士忌
    static async Task Main(string[] args)
    {
    MyClass myClass = await GetAsync();

    Console.WriteLine("All done.");
    Console.ReadKey();
    }
  • HttpResponseMessageIDisposable ,使用正确处理

  • public static async Task<MyClassResponse> GetMyClassResponse()
    {
    using (HttpResponseMessage response = await GetRequestAsync("https://api.example.com/test"))
    {
    return await ParseToMyClassResponse<MyClassResponse>(response);
    }
    }
    并删除 response.Dispose()来自 ParseToMyClassResponse
  • 对于其他测试,我重写了代码以使其更简单。

  • public class Program
    {
    private readonly static HttpClient client = new HttpClient();

    static async Task Main(string[] args)
    {
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token .....");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.Timeout = TimeSpan.FromMilliseconds(10000);
    ServicePointManager.DefaultConnectionLimit = 10;

    try
    {
    MyClassResponse myClassResponse = await GetAPIResponseAsync("https://api.example.com/test");
    MyClass myClass = MyClass.Create(myClassResponse);
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex.Message);
    Console.WriteLine();
    Console.WriteLine(ex.StackTrace);
    }

    Console.WriteLine("All done.");
    Console.ReadKey();
    }

    private static async Task<T> GetAPIResponseAsync<T>(string url)
    {
    using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
    {
    response.EnsureSuccessStatusCode();
    string content = await response.Content.ReadAsStringAsync();
    return JsonConvert.DeserializeObject<T>(content);
    }
    }
    }
    测试这个版本。
    另外不建议更改 SecurityProtocol在代码中,因为它使应用程序易受攻击,请改用默认值。如果要更改 TLS 版本进行测试, edit Windows Registry .

    更新
    我看过源。
    这是一种糟糕的并发编程。您在任务中运行异步函数并阻止正在执行它的任务并同时阻止当前线程。
    Task<PassResponse> task = Task.Run(() => GetPass(scannedValue).Result);
    PassResponse passResponse = task.Result;
    您可以通过这种方式达到相同的结果
    PassResponse passResponse = GetPass(scannedValue).Result;

    再试一次
    让我们改变这一行以避免可能的死锁
    return await _httpClient.GetAsync(new Uri(url));

    return await _httpClient.GetAsync(new Uri(url)).ConfigureAwait(false);
    和这个
    string content = await response.Content.ReadAsStringAsync();

    string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

    关于c# - 调用 httpClient.GetAsync() 时发送任何数据失败,有时会捕获 TaskCanceledException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62590502/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com