【问题标题】:HttpClient c# - A task was canceled at SendASyncHttpClient c# - 在 SendASync 取消了一个任务
【发布时间】:2017-10-11 07:50:38
【问题描述】:

即使我增加了超时,我也会收到TaskCanceledException。令人惊讶的是它甚至不总是发生,异常只在某个时候发生,我无法找到重现错误的模式。我添加了用于进行网络调用的异常跟踪和代码。

public static void getResponseFromUrlAsync<T>(T payload, string url,
     Action<string> onSuccess, Action<string> onFailure)
{
    string contentType = "application/json";
    httpClient = new HttpClient();
    httpClient.Timeout = TimeSpan.FromMinutes(30);
    HttpRequestMessage requestMsg = new HttpRequestMessage();
    requestMsg.RequestUri = new Uri(NetworkCallUrls.baseUri + url);
    Utils.debugLog("Url", NetworkCallUrls.baseUri + url);

    // try
    //{
    string auth = "Bearer " + Objects.GlobalVars.GetValue<string>("access_token"); // //"x1VwaR1otS66ZCTlgtv3X9aaSNpDOn"; //
    httpClient.DefaultRequestHeaders.Add("Authorization", auth);
    requestMsg.Method = HttpMethod.Post;

    requestMsg.Content = new StringContent(
                   Utils.stringifyData(payload),
                   Encoding.UTF8,
                   contentType);

    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header

    makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction(requestMsg, onSuccess, onFailure, progressBarStatus);
}

internal static void disposeConnection(HttpClient httpClient)
{
    httpClient.Dispose();
    httpClient = null;
}

private static async void makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction(
    HttpRequestMessage requestMsg, Action<string> onSuccess,
    Action<string> onFailure, Action<bool> progressBarStatus)
{
    Utils.debugLog("IN MAKE NETWORK CALL 1");
    HttpResponseMessage response = await httpClient.SendAsync(requestMsg);
    Utils.debugLog("IN MAKE NETWORK CALL 2");
    ResponseStatus responseStatus = checkResponseStatusAndExecuteActionAccordinglyAsync(response);
    Utils.debugLog("IN MAKE NETWORK CALL 3");
    if (responseStatus.isSuccess)
    {
        Utils.debugLog("IN MAKE NETWORK CALL 4");
        string responseString = await response.Content.ReadAsStringAsync();
        Utils.debugLog("IN MAKE NETWORK CALL 5");
        onSuccess(responseString);
        Utils.debugLog("IN MAKE NETWORK CALL 6");
    }
    else
    {
        Utils.debugLog("IN MAKE NETWORK CALL 7");
        onFailure(responseStatus.failureResponse);
        Utils.debugLog("IN MAKE NETWORK CALL 8");
    }
    Utils.debugLog("IN MAKE NETWORK CALL 9");
    disposeConnection(httpClient);
    Utils.debugLog("IN MAKE NETWORK CALL 10");
}

我正在使用上面的代码进行 API 调用,我在 HttpResponseMessage response = await httpClient.SendAsync(requestMsg); 行中收到了 TaskCanceledException。

有人可以帮我解决这个问题吗?我在互联网上搜索并增加了超时时间,但没有用。

【问题讨论】:

    标签: c# wpf visual-studio httpclient


    【解决方案1】:

    我希望能帮助您解决问题的一些 cmets:

    1. async 方法应该返回 Task 如果你没有什么要返回,而不是 void。您不必实际返回 Task 对象,编译器会处理它。唯一的例外是 WinForms 和 WebForms 事件处理程序。
    2. 您的getResponseFromUrlAsync 方法不是异步的,但它应该是。您应该添加一个async 修饰符,并返回Task。然后,await makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction(...)。这可能是您的问题的根源 - 您在返回之前没有等待异步操作完成。
    3. 一般来说,您的httpClient 变量似乎是在某个地方全局定义的。您很容易遇到 NullReferenceException,因为即使不先调用 getResponseFromUrlAsync 也可以调用 makeNetworkCallCheckResponseStatusAndExecuteCorrospondingActiondisposeConnection 也可以。如果您的类始终使用httpClient,请在构造函数或声明中对其进行初始化。如果不是,请在方法开始时检查它是否为 null。

    【讨论】:

    • 第二次,我在'makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction'中等待,所以我认为我不需要等待和异步和任务作为'getResponseFromUrlAsync'中的返回
    • @djkp,你会的。 makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction 是异步的,如果你不等待它,你会在它完成执行之前返回。一旦你从 async 开始,它就一直是异步到程序 root 的。
    【解决方案2】:

    您应该等待makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction 方法和getResponseFromUrlAsync 方法。这意味着您需要将返回类型从void 更改为Task

    public static async Task getResponseFromUrlAsync<T>(T payload, string url, Action<string> onSuccess, Action<string> onFailure)
    {
        string contentType = "application/json";
        httpClient = new HttpClient();
        httpClient.Timeout = TimeSpan.FromMinutes(30);
        HttpRequestMessage requestMsg = new HttpRequestMessage();
        requestMsg.RequestUri = new Uri(NetworkCallUrls.baseUri + url);
        Utils.debugLog("Url", NetworkCallUrls.baseUri + url);
    
    
        string auth = "Bearer " + Objects.GlobalVars.GetValue<string>("access_token"); // //"x1VwaR1otS66ZCTlgtv3X9aaSNpDOn"; //
        httpClient.DefaultRequestHeaders.Add("Authorization", auth);
        requestMsg.Method = HttpMethod.Post;
    
        requestMsg.Content = new StringContent(
                       Utils.stringifyData(payload),
                       Encoding.UTF8,
                       contentType);
    
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
    
        await makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction(requestMsg, onSuccess, onFailure, progressBarStatus)
            .ConfigureAwait(false);
    }
    
    internal static void disposeConnection(HttpClient httpClient)
    {
        httpClient.Dispose();
        httpClient = null;
    }
    
    private static async Task makeNetworkCallCheckResponseStatusAndExecuteCorrospondingAction(
        HttpRequestMessage requestMsg, Action<string> onSuccess,
        Action<string> onFailure, Action<bool> progressBarStatus)
    {
        Utils.debugLog("IN MAKE NETWORK CALL 1");
        HttpResponseMessage response = await httpClient.SendAsync(requestMsg).ConfigureAwait(false);
        Utils.debugLog("IN MAKE NETWORK CALL 2");
        ResponseStatus responseStatus = checkResponseStatusAndExecuteActionAccordinglyAsync(response);
        Utils.debugLog("IN MAKE NETWORK CALL 3");
        if (responseStatus.isSuccess)
        {
            Utils.debugLog("IN MAKE NETWORK CALL 4");
            string responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            Utils.debugLog("IN MAKE NETWORK CALL 5");
            onSuccess(responseString);
            Utils.debugLog("IN MAKE NETWORK CALL 6");
        }
        else
        {
            Utils.debugLog("IN MAKE NETWORK CALL 7");
            onFailure(responseStatus.failureResponse);
            Utils.debugLog("IN MAKE NETWORK CALL 8");
        }
        Utils.debugLog("IN MAKE NETWORK CALL 9");
        disposeConnection(httpClient);
        Utils.debugLog("IN MAKE NETWORK CALL 10");
    }
    

    ...和await 调用它时的方法:

    await getResponseFromUrlAsync<..>(...);
    

    【讨论】:

    • 我认为对我来说问题是 httpClient 在 api call_1 完成之前用新的更新,因为我在没有任何延迟的情况下一个接一个地进行多个调用,所以在返回上一个调用之前我打另一个电话
    • 但是我会根据最佳实践更新代码,谢谢 :)
    • 这就是为什么你应该等待方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-11
    • 1970-01-01
    • 2020-08-07
    • 2019-11-17
    相关资源
    最近更新 更多