2016-10-30 4 views
0

Ich versuche, einen HttpError aus einer HttpResponseMessage-Nachricht zu ziehen, die möglicherweise nicht vorhanden ist. Wenn die API eine Ausnahme auslöst, wird sie als HttpError serialisiert, aber Fehler wie 404 werden nicht in diesem Format vorliegen.Lesen eines HttpError-Ergebnisses von HttpResponseMessage ohne Verwendung von Ausnahmen

Ich habe es geschafft, diesen Fehler im unten stehenden Code zu beheben, indem Sie die Ausnahme auslösen, wenn wir den HttpError nicht deserialisieren können.

Das Problem ist jetzt, ich verwende Ausnahme-getriebene Entwicklung.

Idealy Ich möchte so etwas.

var httpError = await response.Content.TryReadAsAsync<HttpError>(formatters); 
if (httpError == null) 
{ 
    // Definetly not an HttpError and no exception thrown 
} 

Sicherlich muss das eine einfache Möglichkeit sein, den Typ des Inhalts im HttpContent zu sagen?

public static async Task<ApiResponseMessage<T>> GetApiResponseAsync<T>(this HttpResponseMessage response, IEnumerable<MediaTypeFormatter> formatters) where T : class 
     {  
      if (!response.IsSuccessStatusCode) 
      { 
       HttpError httpError; 

       // Exception driven programming 
       try 
       { 
        // Could use string? 
        var contentString = response.Content.ReadAsStringAsync(); 

        // This doesn't work. Throws exception if not correct type 
        var contentObject = await response.Content.ReadAsAsync<object>(); 
        var alwaysNull = contentObject as HttpError; 

        httpError = await response.Content.ReadAsAsync<HttpError>(formatters); 
       } 
       catch (Exception) 
       { 
        httpError = null; 
       } 

       return new ApiResponseMessage<T> 
       { 
        IsSuccess = false, 
        HttpError = httpError, 
        Response = response 
       }; 
      } 
      return new ApiResponseMessage<T> 
      { 
       IsSuccess = true, 
       Result = await response.Content.ReadAsAsync<T>(formatters), 
       Response = response 
      }; 
     } 

Antwort

0

Es ist natürlich blendend einfach.

var message = new HttpResponseMessage(); 
HttpError httpError; 
message.TryGetContentValue(out httpError); 

if (httpError != null) 
{ 
    // Do stuff 
} 

Edit:

dies nicht mein Problem beheben, wie der Inhaltstyp nicht vom Typ Object war. Ich habe erwartet, dass der TryGetContentValue auf die gleiche Weise funktioniert wie HttpContent.ReadAsAsync.

Nach dem Durchsuchen des Quellcodes für ReadAsAsync habe ich eine funktionierende Lösung erstellt.

public class ReadAsyncResult<T> 
     { 
      public ReadAsyncResult() 
      { 
      } 

      public ReadAsyncResult(T result) 
      { 
       Result = result; 
       IsSuccess = result != null; 
      } 

      public T Result { get; set; } 
      public bool IsSuccess { get; set; } 
     } 

     public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(this HttpContent content) 
     { 
      return await TryReadAsAsync<T>(content, CancellationToken.None); 
     } 

     public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(this HttpContent content, CancellationToken cancellationToken) 
     { 
      if (content == null) 
       return new ReadAsyncResult<T>(); 

      var type = typeof(T); 

      var objectContent = content as ObjectContent; 

      if (objectContent?.Value != null && type.IsInstanceOfType(objectContent.Value)) 
      { 
       return new ReadAsyncResult<T>((T)objectContent.Value); 
      } 

      var mediaType = content.Headers.ContentType; 
      var reader = new MediaTypeFormatterCollection(new MediaTypeFormatterCollection()).FindReader(type, mediaType); 

      if (reader == null) return new ReadAsyncResult<T>(); 

      var value = await ReadAsAsyncCore<T>(content, type, reader, cancellationToken); 
      return new ReadAsyncResult<T>(value); 
     } 

     private static async Task<T> ReadAsAsyncCore<T>(HttpContent content, Type type, MediaTypeFormatter formatter, CancellationToken cancellationToken) 
     { 
      cancellationToken.ThrowIfCancellationRequested(); 

      var stream = await content.ReadAsStreamAsync(); 
      var result = await formatter.ReadFromStreamAsync(type, stream, content, null, cancellationToken); 

      return (T) result; 
     } 
Verwandte Themen