Skip to content

Proposal: HttpRequestException w/ Status Code #911

@yaakov-h

Description

@yaakov-h

Latest Proposal

HttpRequestException.StatusCode property

Rationale and Usage

A new nullable HttpRequestException.StatusCode property exposes a response's status code if it has been already received, otherwise it's set to null. This will enable a direct access to the status code on exceptions thrown from HttpClient's simple GET methods and HttpResponseMessage.EnsureSuccessStatusCode(). New HttpRequestException constructors taking a status code will initialize that property.

try
{
    string response = httpClient.GetStringAsync(requestUri);
    ...
}
catch(HttpRequestException e)
{
    if (e.StatusCode == HttpStatusCode.MovedPermanently)
    {
       ...
    }
}

Proposed API

public class HttpRequestException : Exception
{
        ...
+       public HttpStatusCode? StatusCode { get; }
        
        public HttpRequestException(string message)
        {...}

+       public HttpRequestException(string message, HttpStatusCode? statusCode)
+       {...}

        public HttpRequestException(string message, Exception inner)
        {...}

+       public HttpRequestException(string message, Exception inner, HttpStatusCode? statusCode)
+       {...}
}

Original Proposal

Proposed solution to dotnet/corefx#9227, dotnet/corefx#24253 and any related issues:

Linking in SteamRE/SteamKit#517 as well.

I've had the following issue in various codebases:

  1. Some HTTP-based code expects a 200-series response.
  2. The HTTP-based code uses HttpResponseMessage.EnsureSuccessStatusCode()
  3. The calling code catches the exception and wants to do something based on the status code.
  4. The calling code does not have access to the original HTTP response status code, or any headers, etc.

In the old .NET HTTP APIs, this was straightforward because WebException includes the status code and the response object, where available.

Adding StatusCode to HttpRequestException has been rejected in the above-linked issues due to it being of little use in most cases.

Would it be possible instead to create a subclass of HttpRequestException, and have EnsureSuccessStatusCode() throw that instead?

Something resembling the following ought to do the trick:

public class HttpResponseException : HttpRequestException
{
    public HttpResponseException()
    {
        ...
    }

    public HttpResponseException(string message, Exception innerException)
    {
        ...
    }

    public HttpResponseException(string message, int statusCode)
    {
        ...
    }

    public HttpResponseException(string message, int statusCode, Exception innerException)
    {
        ...
    }

    public int StatusCode { get; }
}

This would achieve the following:

  1. HttpRequestException does not have a majority-useless field.
  2. Code that catches HttpRequestException would continue to function as-is.
  3. Networking errors, unreachable servers etc. will continue to throw HttpRequestException.
  4. New code can opt in to catching HttpResponseException, and will then have access to the original HTTP Status Code.

Optionally, for consideration, the exception could also include the whole HttpResponseMessage object in line with good old WebException.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions