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