Search code examples
c#asp.net-core-webapiasp.net-core-2.1

.NET Core WebApi Get HttpClient Error Message


I am trying to display the relevant error message returned from a Web API when using HttpClient.PostJsonAsync<T>().

In my Web API, for example on a failed login I would return a 401 unauthorized exception with the message in the body with an error handling middleware;

public class HttpErrorHandlerMiddleware
{
    private readonly RequestDelegate _next;

    public HttpErrorHandlerMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (HttpStatusCodeException exception)
        {
            if (!context.Response.HasStarted)
            {
                context.Response.StatusCode = (int)exception.StatusCode;
                context.Response.Headers.Clear();
                await context.Response.WriteAsync(exception.Message);
            }
        }
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class HttpErrorHandlerMiddlewareExtensions
{
    public static IApplicationBuilder UseHttpErrorHandlerMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<HttpErrorHandlerMiddleware>();
    }
}

Then in Postman this is displayed with the message e.g. 'Invalid UserName or Password', 'User is Locked out.', etc.

However, when I try to catch the error on the client side, e.g.

try
{
    var result = await _httpClient.PostJsonAsync<LoginResponse>("api/login", loginModel);

    /* Removed for brevity */
}
catch(Exception ex)
{
     return new LoginResponse { Success = false, Error = ex.Message };
}

The error returned is always 'Response status code does not indicate success: 401 (Unauthorized).'

How would I get the detail of the error from the return of the PostJsonAsync<T> please?


Solution

  • 401 is a validate response, and it would not be captured in HttpErrorHandlerMiddleware.

    I am not sure how you implement 401 and PostJsonAsync. Here is a working demo for you:

    1. Controller Action

      [HttpPost]
      public IActionResult Login(LoginModel loginModel)
      {
          return StatusCode(401, new LoginResponse {
              Success = false,
              Error = "Invalid User Name and Password"
          });
      }
      
    2. HttpClient Request

      public async Task<LoginResponse> Test(LoginModel loginModel)
      {
          var _httpClient = new HttpClient();
          var result = await _httpClient.PostAsJsonAsync<LoginModel>("https://localhost:44322/api/values/login", loginModel);
          return await result.Content.ReadAsAsync<LoginResponse>();
      }