正确使用EnsureSuccessStatusCode和IsSuccessStatusCode

时间:2017-08-17 15:50:39

标签: c# asp.net-web-api exception-handling httpresponse

我使用HttpClient调用我的Web API,我发现有一个EnsureSuccessStatusCode方法和一个IsSuccessStatusCode属性。哪一个合适?

我读了这篇文章,还有一些问题:

Usage of EnsureSuccessStatusCode and handling of HttpRequestException it throws

我遇到的问题是,如果我发送一个GET请求,我传递了我想要检索的对象的ID,那么基本上有两个结果:

  1. 我以状态200
  2. 返回对象
  3. 我可能因为没有匹配而返回null,但这会导致状态为404。
  4. 如果我调用EnsureSuccessStatusCode()状态404将导致抛出异常。这并不理想,因为当我测试我的代码时,我一直收到404错误,这首先让我觉得API URL不正确,但实际上没有匹配的对象与提供的Id。在这种情况下,我宁愿返回一个null对象而不是抛出异常。

    所以我尝试检查IsSuccessfulStatusCode属性的值。这似乎是一个更好的选择,当此属性为false时,我可以返回一个null对象,但是,有许多状态代码可能导致此属性具有false值。 404是其中之一,但还有其他几个状态代码,例如 400 Bad Request 405 Method Not Allowed 等等。我想记录一个例外除404之外的所有不成功的错误代码我想知道是否有更好的方法来检查响应的ResponseCode值,然后抛出一个异常,我的catch块被捕获,这是记录发生。

    以下是我的GET方法的代码:

    public static Customer GetCustomerByID(int id)
    {
        try
            {
                using (var client = GetConfiguredClient())
                {
                    Customer customer = null;
                    var requestUri = $"Customers/{id}";
    
                    using (var response = client.GetAsync(requestUri).Result)
                    {
                        if (response.IsSuccessStatusCode)
                            customer = response.Content.ReadAsAsync<Customer>().Result;
                    }
    
                    return customer;
                }
            }
            catch (Exception ex)
            {
              ex.Data.Add(nameof(id), id);
    
              LogException(ex);
    
              throw;
            }
        }
    

    如果返回一个未成功的状态代码并且没有记录任何内容,则此代码将返回null Customer

    处理这种情况的最佳方法是什么?

3 个答案:

答案 0 :(得分:6)

因此:

  

所以我尝试检查IsSuccessfulStatusCode的值   属性。这似乎是一个更好的选择,我可以返回null   但是,当此属性为false时,对象有很多状态   可能导致此属性具有错误值的代码。 404是   其中一个,但还有其他几个状态代码,如400 Bad   请求,405方法不允许等。我想记录异常   所有不成功的错误代码除了404和我想知道是否   有一种比检查ResponseCode更好的方法   响应的值,然后抛出一个被捕获的异常   通过我的catch块,这是记录发生的地方。

我会使用EnsureSuccessStatusCode方法然后修改catch块,如下所示:

public static Customer GetCustomerByID(int id)
{
    try
    {
        using (var client = GetConfiguredClient())
        {
            var requestUri = $"Customers/{id}";
            Customer customer;

            using (var response = client.GetAsync(requestUri).Result)
            {
                try 
                {
                    response.EnsureSuccessStatusCode();
                    // If we reach here it means we can get the customer data.
                    customer = response.Content.ReadAsAsync<Customer>().Result;
                }
                catch(HttpRequestException)
                {
                    if(response.StatusCode == HttpStatusCode.NotFound) // 404
                    {
                        customer = null;
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            return customer;
        }
    }
    catch (Exception ex)
    {
        ex.Data.Add(nameof(id), id);

        LogException(ex);

        throw;
    }
}

答案 1 :(得分:1)

根据本文档:https://docs.microsoft.com/en-us/windows/uwp/networking/httpclient 解决后可以没问题:

Uri requestUri = new Uri("http://www.contoso.com");

//Send the GET request asynchronously and retrieve the response as a string.
Windows.Web.Http.HttpResponseMessage httpResponse = new 
Windows.Web.Http.HttpResponseMessage();
string httpResponseBody = "";

try
{
    //Send the GET request
    httpResponse = await httpClient.GetAsync(requestUri);
    httpResponse.EnsureSuccessStatusCode();
    httpResponseBody = await httpResponse.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
    httpResponseBody = "Error: " + ex.HResult.ToString("X") + " Message: " + ex.Message;
}

但是:httpResponse.EnsureSuccessStatusCode(); ==状态码从200到299

我使用的是HttpStatusCode。OK= 200 =是SecureSuccessStatusCode的SUB-PART,表示请求成功,并且请求的信息在响应中。

HttpResponseMessage result = await this._httpClient.GetAsync("https://www.web1.com/getThis", cancellationToken);
if (result.StatusCode != HttpStatusCode.OK)
{
    return new HttpResponseMessage(result.StatusCode)
    {
        Content = new StringContent( "ERROR DESCRIPTION HERE")
    };
}
return result;  // I can return here HttpResponseMessage....

答案 2 :(得分:0)

  1. 如果要处理特定的错误响应,请使用if语句直接处理它们(在调用EnsureSuccessStatusCode之前)。
  2. 如果要将所有(其余)错误响应都视为意外错误,请使用EnsureSuccessStatusCode并将异常传递到可以实际对其进行处理的下一个位置(这可能是通用错误处理程序,位于程序的最高级别,您的Web框架等)。
  3. 如果您想对所有(其余)错误响应(例如日志记录)执行某项操作,但随后又可以正常进行,或者如果您想抛出自己的异常类型,请使用IsSuccessStatusCode

这种方法为您提供了异常的所有优点,同时最大限度地减少了不利因素(例如,在您可能不感兴趣的完全正常的事件中中断调试器,或者使用catch块代替代码,这些代码很难阅读和理解。而不是if语句。

示例:

using (var response = client.GetAsync(requestUri).Result)
{
  if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
  {
    // special handling for "401 Unauthorized"
  }
  else  
    response.EnsureSuccessStatusCode();

  // Handle successful response
}

...或者如果您想读取错误响应或进行日志记录等:

using (var response = client.GetAsync(requestUri).Result)
{
  if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
  {
    // special handling for "401 Unauthorized"
  }
  else if (!response.IsSuccessStatusCode)
  {
    // Read error response, logging, throw custom exception, etc.

    // ... and if you still want to throw the standard exception:
    response.EnsureSuccessStatusCode();
  }
  else
  {
    // Handle successful response
  }
}