Asp.net web api 处理来自类型化WebAPI HttpClient调用的错误
我对webapi客户端进行了多次调用,这些调用返回一个任务 像这样的Asp.net web api 处理来自类型化WebAPI HttpClient调用的错误,asp.net-web-api,error-handling,async-await,dotnet-httpclient,Asp.net Web Api,Error Handling,Async Await,Dotnet Httpclient,我对webapi客户端进行了多次调用,这些调用返回一个任务 像这样的 public async Task<TResp> GetMyThingAsync(TReq req) { using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri(BaseURI); client.DefaultRequestHeaders.Accept.Clear();
public async Task<TResp> GetMyThingAsync(TReq req)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(BaseURI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/xml"));
await HttpRuntime.Cache.GetToken().ContinueWith((t) =>
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("XXX", t.Result);
});
var httpResponseMessage = await client.PostAsXmlAsync<TReq>("This/That/", req);
httpResponseMessage.EnsureSuccessStatusCode();
var resp = await httpResponseMessage.Content.ReadAsAsync<TResp>();
return resp;
}
}
这是路吗?ErroMessageHandler看起来是什么样子,并且做什么来向调用控制器返回有用的东西
非常感谢
nat创建自定义处理程序是记录异常或验证响应的优雅解决方案。如果被调用的控制器遇到异常,我不确定它是否正在等待来自客户端的有意义的响应。我认为真正重要的部分是确保您(客户机)优雅地处理web API错误 这可以通过两种方式实现:
HttpResponseMessage.IsSuccessStatusCode
属性,该属性指示是否返回错误响应,而不是调用引发异常的HttpResponseMessage.EnsureAccessStatusCode()
,并返回自定义错误响应(或执行您决定的操作):
您好,谢谢您的回复,但是我不能从GetMyThingAsync方法返回除键入的响应之外的任何东西(我想可能是错误的),因为它只返回一个TResp(或其他什么),所以我如何让它返回一个ErrorResponse?同样地,对于DelegatingHandler,我可以记录东西,但是如何将东西返回到控制器而不引发异常?什么类型是
TResp
?里面有什么?还有,你为什么要这么做?控制器正在等待你返回有效的响应吗?嗨,Yuval,也许我所有的调用都愚蠢地返回了方法本身的类型化响应。。因此,对GetAvailability方法的调用将返回AvailabilityResponse对象。。我是否应该创建一个更通用的客户机,如果它没有返回一个出现故障的通用HttpMessageResponse,我可以在以后对其进行分析。。?我想使用DelgatingHandler来处理添加授权头的问题,而不是为每个不同的方法复制授权头。所以可能一些通用的东西会更合适基本上我有很多API调用要进行,所有调用都返回不同的对象,我为这些对象编写了类,我为每个对象编写了一个方法,返回类型化结果您的响应对象都可以派生自一个公共的ResponseBase
,它有一个StatusCode
属性和一个Exception
属性,如果在获取数据时发生错误/异常,将填充该属性
var customHandler = new ErrorMessageHandler()
{ InnerHandler = new HttpClientHandler()};
HttpClient client = new HttpClient(customHandler);
var client = new HttpClient() // No need to dispose HttpClient
client.BaseAddress = new Uri(BaseURI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/xml"));
var token = await HttpRuntime.Cache.GetToken();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("XXX", token);
var httpResponseMessage = await client.PostAsXmlAsync<TReq>("This/That/", req);
if (!httpResponseMessage.IsSuccessStatusCode)
{
return Task.FromResult(new ErrorResponse()) // Create some kind of error response to indicate failure
}
var resp = await httpResponseMessage.Content.ReadAsAsync<TResp>();
return resp;
public class ErrorLoggingHandler : DelegatingHandler
{
private readonly StreamWriter _writer; // As a sample, log to a StreamWriter
public ErrorLoggingHandler(Stream stream)
{
_writer = new StreamWriter(stream);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode)
{
// This would probably be replaced with real error
// handling logic (return some kind of special response etc..)
_writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri,
(int) response.StatusCode, response.Headers.Date);
}
return response;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_writer.Dispose();
}
base.Dispose(disposing);
}
}
var httpclient = HttpClientFactory.Create(new ErrorLoggingHandler(new FileStream(@"Location", FileMode.OpenOrCreate)));