0

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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew Flynn
  • 3,661
  • 7
  • 40
  • 98
  • 1
    because it doesn't consider your messasge is the exception reason. You can always return a message "Everything was done perfectly" with your 401. To get the message, read the body returned from client – NoName Aug 20 '19 at 15:18
  • @TuyenPham how would I read the body from the return exception from `PostJsonAsync` please? – Matthew Flynn Aug 20 '19 at 15:26
  • intead of `PostJsonAsync`, you can use `PostAsync`, which allow you to read the content when there is an exception: https://stackoverflow.com/a/39414248/1560697 – NoName Aug 20 '19 at 15:29
  • How did you return `401` with `Invalid UserName or Password` in the body? What is `PostJsonAsync`? – Edward Aug 21 '19 at 02:33

1 Answers1

3

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>();
    }
    
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Edward
  • 28,296
  • 11
  • 76
  • 121