【问题标题】:Reading an HttpError result from HttpResponseMessage without using exceptions从 HttpResponseMessage 读取 HttpError 结果而不使用异常
【发布时间】:2016-10-30 20:02:05
【问题描述】:

我正在尝试从可能存在或不存在的 HttpResponseMessage 消息中提取 HttpError。如果 Api 抛出异常,它将被序列化为 HttpError 但是诸如 404 之类的错误不会采用这种格式。

如果我们未能反序列化 HttpError,我已设法通过捕获引发的异常来修复以下代码中的此错误。

问题是我现在正在使用异常驱动的开发。

理想情况下,我想要这样的东西。

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

肯定是一种简单的方法来告诉 HttpContent 中的内容类型吗?

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
            };
        }

【问题讨论】:

    标签: c# asp.net asp.net-web-api casting asp.net-web-api2


    【解决方案1】:

    清理代码,使其至少可以编译。

     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>(HttpContent content)
        {
            return await TryReadAsAsync<T>(content, CancellationToken.None);
        }
    
        public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      当然,非常简单。

      var message = new HttpResponseMessage();
      HttpError httpError;
      message.TryGetContentValue(out httpError);
      
      if (httpError != null)
      {
          // Do stuff
      }
      

      编辑:

      这并没有解决我的问题,因为内容类型不是 ObjectResult 类型。我期待 TryGetContentValue 以与 HttpContent.ReadAsAsync 相同的方式工作。

      在深入研究 ReadAsAsync 的源代码后,我创建了一个可行的解决方案。

         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;
              } 
      

      【讨论】:

      • 嗨。是否可以稍微清理一下代码?照原样,代码不起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多