378 Stimmen

HttpClient.GetAsync(...) gibt bei Verwendung von await/async nie zurück

Edita: Diese Frage sieht so aus, als ob es sich um dasselbe Problem handeln könnte, hat aber keine Antworten...

Edita: Im Testfall 5 scheint die Aufgabe in der folgenden Situation stecken zu bleiben WaitingForActivation Zustand.

Ich habe einige seltsame Verhalten mit dem System.Net.Http.HttpClient in .NET 4.5 - wo "warten" das Ergebnis eines Aufrufs an (z. B.) gefunden. httpClient.GetAsync(...) wird niemals zurückkehren.

Dies tritt nur unter bestimmten Umständen auf, wenn die neue async/await-Sprachfunktionalität und die Tasks-API verwendet werden - der Code scheint immer zu funktionieren, wenn nur Fortsetzungen verwendet werden.

Hier ist etwas Code, der das Problem reproduziert - legen Sie diese in ein neues "MVC 4 WebApi-Projekt" in Visual Studio 11, um die folgenden GET-Endpunkte freizugeben:

/api/test1
/api/test2
/api/test3
/api/test4
/api/test5 <--- never completes
/api/test6

Jeder der Endpunkte hier gibt die gleichen Daten zurück (die Antwort-Header von stackoverflow.com), mit Ausnahme von /api/test5 die niemals abgeschlossen wird.

Bin ich auf einen Fehler in der HttpClient-Klasse gestoßen, oder verwende ich die API auf irgendeine Weise falsch?

Code zum Reproduzieren:

public class BaseApiController : ApiController
{
    /// <summary>
    /// Retrieves data using continuations
    /// </summary>
    protected Task<string> Continuations_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var t = httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead);

        return t.ContinueWith(t1 => t1.Result.Content.Headers.ToString());
    }

    /// <summary>
    /// Retrieves data using async/await
    /// </summary>
    protected async Task<string> AsyncAwait_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var result = await httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead);

        return result.Content.Headers.ToString();
    }
}

public class Test1Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await Continuations_GetSomeDataAsync();

        return data;
    }
}

public class Test2Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = Continuations_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test3Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return Continuations_GetSomeDataAsync();
    }
}

public class Test4Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await AsyncAwait_GetSomeDataAsync();

        return data;
    }
}

public class Test5Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = AsyncAwait_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test6Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return AsyncAwait_GetSomeDataAsync();
    }
}

2voto

Alexey Podlasov Punkte 925

In meinem Fall wurde "await" nie beendet, weil bei der Ausführung der Anfrage eine Ausnahme auftrat, z. B. weil der Server nicht antwortete usw. Umgeben Sie es mit try..catch, um festzustellen, was passiert ist, wird es auch Ihre "await" anmutig beenden.

public async Task<Stuff> GetStuff(string id)
{
    string path = $"/api/v2/stuff/{id}";
    try
    {
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.StatusCode == HttpStatusCode.OK)
        {
            string json = await response.Content.ReadAsStringAsync();
            return JsonUtility.FromJson<Stuff>(json);
        }
        else
        {
            Debug.LogError($"Could not retrieve stuff {id}");
        }
    }
    catch (Exception exception)
    {
        Debug.LogError($"Exception when retrieving stuff {exception}");
    }
    return null;
}

2voto

Shahid Islam Punkte 510

Ich benutzte zu viele Wartezeiten, so dass ich keine Antwort erhielt, ich konvertierte in einen Sync-Aufruf, der jetzt funktioniert.

            using (var client = new HttpClient())
            using (var request = new HttpRequestMessage())
            {
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                request.Method = HttpMethod.Get;
                request.RequestUri = new Uri(URL);
                var response = client.GetAsync(URL).Result;
                response.EnsureSuccessStatusCode();
                string responseBody = response.Content.ReadAsStringAsync().Result;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X