Asp.net web api 处理来自类型化WebAPI HttpClient调用的错误

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();

我对webapi客户端进行了多次调用,这些调用返回一个任务 像这样的

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