从HttpResponseMessage读取HttpError结果而不使用异常

时间:2016-10-30 20:02:05

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

我试图从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
            };
        }

2 个答案:

答案 0 :(得分: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;
    }
}

答案 1 :(得分:0)

当然,这非常简单。

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