16

I've googled a lot searching for an answer to my problem with no luck so, let's try if someone else can help me.

I have a Web Api 2 action to register an user after doing some validations. If everything works, it return the serialized user and if don't, an error message sent within a BadRequest response.

At the other hand, I have a WPF client that calls the API for a response.

My problem is that I can't get the reason sent by the error, the client just get the Bad Request error message.

This is a part of the code:

  • Web Api Action:

    public async Task<IHttpActionResult> AddUser(NewUserDTO {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        if (!model.IdCliente.HasValue)
        {
            ModelState.AddModelError("", "No existe el cliente");
            return BadRequest(ModelState);
        }
        // do save stuff
        return Ok(TheModelFactory.Create(user));
    }
    
  • Client function:

    public async Task<ApplicationUserDTO> AddUser(NewUserDTO dto) {
        using (var client = new HttpClient()) {
            client.BaseAddress = new Uri(_urlBase);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
            HttpContent content = new StringContent(JsonConvert.SerializeObject(dto));
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            HttpResponseMessage responseMessage = await client.PostAsync("api/accounts/AddUser", content);
            if (responseMessage.IsSuccessStatusCode) {
                var responseJson = await responseMessage.Content.ReadAsStringAsync();
                user = JsonConvert.DeserializeObject<ApplicationUserDTO>(responseJson);
            }
            else
                 MessageBox.Show(responseMessage.Content.ReadAsStringAsync().Result);
            return user;
        } 
    }
    

Anyone can help?

Edited:

  • DTO:

    [Serializable]
    public class NewUserDTO {
    public int? IdCliente { get; set; }
    [Required]
    public string UserName { get; set; }
    [Required]
    public string Email { get; set; }
    public string Role { get; set; }
    public string Password { get; set; } }
    

Anyway... the dto is sent correctly to api nut, here's the serialized dto as you asked for:

"{\"IdCliente\":null,\"UserName\":\"Toni\",\"Email\":\"[email protected]\",\"Role\":\"Filtra\",\"Password\":\"TONI\"}"
4
  • Can you put debug point at line HttpContent content = new StringContent(JsonConvert.SerializeObject(dto)); and post value of content? Also definition of NewUserDTO type as well. Commented Feb 22, 2016 at 1:24
  • Added the code requested Commented Feb 22, 2016 at 21:53
  • @ToniMoreno Can you post where you add your filters if you have any Commented Feb 23, 2016 at 9:36
  • code public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute());} Commented Feb 23, 2016 at 17:45

5 Answers 5

16

API

return new BadRequestErrorMessageResult(yourErrorMessage);

Client

var errorMessage = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
MessageBox.Show(errorMessage);
Sign up to request clarification or add additional context in comments.

Comments

10

Have you checked your web.config httpErrors section?

I had the same issue because my web.config looked like this

<httpErrors errorMode="Custom" existingResponse="Replace">
    <clear />
    <error statusCode="404" path="~/Error/NotFound" responseMode="ExecuteURL" />
    <error statusCode="403" path="~/Error/AccessDenied" responseMode="ExecuteURL" />
    <error statusCode="500" path="~/Error/ServerError" responseMode="ExecuteURL" />
</httpErrors>

You must make sure that existingResponse is set to PassThrough

<httpErrors errorMode="Custom" existingResponse="PassThrough">
    <clear />
    <error statusCode="404" path="~/Error/NotFound" responseMode="ExecuteURL" />
    <error statusCode="403" path="~/Error/AccessDenied" responseMode="ExecuteURL" />
    <error statusCode="500" path="~/Error/ServerError" responseMode="ExecuteURL" />
</httpErrors>

Not sure if it will help you, but give it a shot.

Comments

2

Instead of returning it, throw a request exception:

throw new HttpResponseException(HttpStatusCode.BadRequest);

Unless you require more detail passing o the client in which case you could pass back a Request.CreateErrorResponse but you would need to change the return type to HttpResponseMessage

3 Comments

It doesn't work. I guess the error is cached by any filter and it returns to the client the html source code for the Internal Server Error page.
@ToniMoreno Sorry quick, corrected now. Possible duplicate here to, have a look at this: stackoverflow.com/questions/12519561/…
Making this change to return an HttpResponseException then adding the error detail policy I posted should return your the error details!
1

Add the line below to WebAPIConfig.cs in the Register method. This will include the error details instead of just the generic 500 internal server error.

        GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

Comments

1

Finally, I gived up. Maybe some code at web.config, mvc config, api config, filtering or whatever is disturbing and sending a diferent response than the controller does. I added a status code and a message property to my DTO and return always an object. Thanks anyway to all who tried to help me.

1 Comment

What does "gived up" mean? Stackovflow is allowing such language.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.