7

Ich habe eine FileResult : IHttpActionResult Webapi Rückgabetyp für meine API-Anrufe erstellt. Das FileResult lädt eine Datei von einer anderen URL herunter und gibt den Stream dann an den Client zurück.HttpClient in der Verwendung der Anweisung verursacht Aufgabe abgebrochen

Zunächst hatte meinen Code ein using Aussage wie folgt:

public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
{ 
    try 
    { 
     HttpResponseMessage response; 
     using (var httpClient = new HttpClient()) 
     { 

      response = new HttpResponseMessage(HttpStatusCode.OK) 
      { 
       Content = new System.Net.Http.StreamContent(
            await httpClient.GetStreamAsync(this.filePath)) 
      }; 
     } 
     return response; 
    } 
    catch (WebException exception) 
    {...} 
} 

dies jedoch intermittierend eine TaskCanceledException verursachen würde. Ich weiß, dass, wenn der HttpClient vor dem asynchronen Aufruf beendet wird, der Status der Task in abgebrochen geändert wird. Da ich jedoch erwarte in: , die verhindern sollte, dass der HttpClient in der Mitte der Task abgeschlossen veräußert werden.

Warum wird diese Aufgabe abgebrochen? Es ist nicht wegen einer Zeitüberschreitung, da dies bei den kleinsten Anfragen passiert ist und nicht immer bei großen Anfragen auftritt.

Wenn ich entfernt die using Anweisung der Code richtig gearbeitet:

public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
{ 
    try 
    { 
     HttpResponseMessage response; 
     var httpClient = new HttpClient(); 

     response = new HttpResponseMessage(HttpStatusCode.OK) 
     { 
      Content = new System.Net.Http.StreamContent(
           await httpClient.GetStreamAsync(this.filePath)) 
     }; 
     return response; 
    } 
    catch (WebException exception) 
    {...} 
} 

Jede Idee, warum das mit dem Problem verursacht?

+0

Haben Sie versucht, einen Debugger zu verwenden? Überprüfen Sie es Schritt für Schritt. – kevintjuh93

+0

Ja, ich habe. Es hilft nicht wirklich, da die Ausnahme nicht hier, sondern an einem völlig anderen Ort ausgelöst wird. Es kommt in der Owin-Pipeline vor, die ich verwende, wo die Authentifizierung ist und es wartet auf die nächste Anfrage. – Rafi

+0

Hat die 'TaskCanceledException' eine innere Ausnahme? –

Antwort

9

Ich weiß, dass, wenn der Httpclient angeordnet ist, bevor der asychronous Anruf beendet ist Staates, die Aufgabe abgebrochen wird sich ändern. Da ich jedoch eine Wartezeit in: Content = new System.Net.Http.StreamContent (http httpClient.GetStreamAsync (this.filePath)) verwende, sollte verhindert werden, dass der HttpClient mitten in der Beendigung der Aufgabe entsorgt wird.

Aber was macht diese Aufgabe ? Es wird der Stream. Also, Ihr Code endet mit einem Stream, die möglicherweise oder nicht vollständig gelesen werden, wenn es die HttpClient schließt.

HttpClient ist speziell für die Wiederverwendung (und gleichzeitigen Gebrauch), so dass ich empfehlen die using vollständig und Bewegen der HttpClient Erklärung einer static Klassenmitglied zu entfernen. Aber wenn Sie die Clients schließen und erneut öffnen möchten, sollten Sie in der Lage sein, es von lesen den Stream vollständig in den Speicher vor dem Schließen der HttpClient.

4

Ich hatte ein ähnliches Problem mit Task abgebrochen Ausnahmen. Wenn Sie AggregateException versuchen fangen oder einem Haken all Exception Block unter Ihren WebException mit, finden Sie auch, dass Sie es fangen, mit einer Ausnahme mit dem Eintrag unter Angabe „A Aufgabe abgebrochen wurde“

ich einige Untersuchungen gemacht und festgestellt, dass die AggregateException ist ziemlich irreführend, wie in verschiedenen Themen beschrieben;

Setting HttpClient to a too short timeout crashes process

How can I tell when HttpClient has timed out?

Bug in httpclientgetasync should throw webexception not taskcanceledexception

landete ich meinen Code ändern auf einen expliziten Timeout zu setzen (wo asyncTimeoutInMins aus der app.config-Datei gelesen wird);

 string jsonResponse = string.Empty; 
     try 
     { 
      using (HttpClient httpClient = new HttpClient()) 
      { 
       httpClient.BaseAddress = new Uri(Properties.Settings.Default.MyWebService); 
       httpClient.DefaultRequestHeaders.Accept.Clear(); 
       httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
       httpClient.Timeout = new TimeSpan(0, asyncTimeoutInMins, 0); 

       HttpResponseMessage response; 

       response = await httpClient.GetAsync("/myservice/resource"); 

       // Check the response StatusCode 
       if (response.IsSuccessStatusCode) 
       { 
        // Read the content of the response into a string 
        jsonResponse = await response.Content.ReadAsStringAsync(); 
       } 
       else if (response.StatusCode == HttpStatusCode.Forbidden) 
       { 
        jsonResponse = await response.Content.ReadAsStringAsync(); 

        Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse))); 

        Environment.Exit((int)ExitCodes.Unauthorised); 
       } 
       else 
       { 
        jsonResponse = await response.Content.ReadAsStringAsync(); 

        Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse))); 

        Environment.Exit((int)ExitCodes.ApplicationError); 
       } 
      } 

     } 
     catch (HttpRequestException reqEx) 
     { 
      Logger.Instance.Error(reqEx); 

      Console.WriteLine("HttpRequestException : {0}", reqEx.InnerException.Message); 

      Environment.Exit((int)ExitCodes.ApplicationError); 
     } 
     catch (Exception ex) 
     { 
      Logger.Instance.Error(ex); 

      throw; 
     } 

     return jsonResponse; 
+0

Wie im obigen Kommentar erwähnt, wird die Ausnahme dort nicht abgefangen, sondern im Authentifizierungslogik-Layer. – Rafi

Verwandte Themen