1

In my IdentityConfig.cs

   manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

In my Web MVC UI, this is my action method

HttpResponseMessage responsePost = GlobalVariables.WebApiClient.PostAsJsonAsync("Account/Register", registerBindingModel).Result;
        if (responsePost.IsSuccessStatusCode)
        {
                ViewBag.Message = "Added";
        }
        else
        {
            ViewBag.Message = "Internal server Error: " + responsePost.ReasonPhrase;
        }

The code works. I can post data if it passes validation logic for passwords. But if it fails, it just throw back Internal server Error: Bad Request to my ui. But when I test it using Postman, I can see the error message from identity. Example Passwords must have at least one lowercase ('a'-'z').

Where this error message stored in HttpResponseMessage?

enter image description here

The API method for Register

[AllowAnonymous]
    [HttpPost]
    [Route("Register")]
    public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

        IdentityResult result = await UserManager.CreateAsync(user, model.Password);

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
    }

private IHttpActionResult GetErrorResult(IdentityResult result)
    {
        if (result == null)
        {
            return InternalServerError();
        }

        if (!result.Succeeded)
        {
            if (result.Errors != null)
            {
                foreach (string error in result.Errors)
                {
                    ModelState.AddModelError("", error);
                }
            }

            if (ModelState.IsValid)
            {
                // No ModelState errors are available to send, so just return an empty BadRequest.
                return BadRequest();
            }

            return BadRequest(ModelState);
        }

        return null;
    }
Steve
  • 2,963
  • 15
  • 61
  • 133
  • 1
    HttpResponseMessage class has content property. You need to read value of that property. https://stackoverflow.com/questions/29975001/how-to-read-httpresponsemessage-content-as-text – Chetan Jan 24 '20 at 03:48
  • @ChetanRanpariya now I can read the error using `var content = responsePost.Content.ReadAsStringAsync(); ViewBag.Message = "Error: " + content.Result;` But its output is `Error: {"$id":"1","Message":"The request is invalid.","ModelState":{"$id":"2","":["Passwords must have at least one lowercase ('a'-'z')."]}}`. How to I read just the `ModelState` error message? – Steve Jan 24 '20 at 05:11

1 Answers1

1

Based upon the comments, you need to parse the string content which returns a JSON string assuming your API is designed in that manner.

I am not sure about your API code but if you need to send your ModelState, you can send it in JSON form using:

return Json(ModelState);

You should not use IsSuccessStatusCode for a way to check for your logic. Basically it is a value that indicates if the HTTP response was successful. It is true if HttpStatusCode was in the Successful range (200-299); otherwise false. The algorithm for IsSuccessStatusCode is shown below:

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}

You can clearly see that the above function only depends on the statusCode received from the API.

Therefore you need to define your logic based on the content that you receive from the API. Create a model that will hold the response from the API based on the condition that you define in the API.

HttpResponseMessage responsePost = GlobalVariables.WebApiClient.PostAsJsonAsync("Account/Register", registerBindingModel).Result;
MyAPIResponse model=new MyAPIResponse();
string content=string.Empty;

    if (responsePost.IsSuccessStatusCode)
    {
      content = response.Content.ReadAsStringAsync().Result;
      model = JsonConvert.DeserializeObject<MyAPIResponse>(content); 
      //or if you do not want a model structure for the parsing
      //var parsedmodel = JsonConvert.DeserializeObject<dynamic>(content);                   
    }

    ViewBag.Message=model.message;

I was not able to parse the content posted in your comment since it is not a valid JSON string. You would need to generate the correct JSON format for your logic.

EDIT:

So you can send the ModelState errors as JSON using a extension method:

public static class ModelStateHelper
{
    public static IEnumerable Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState.ToDictionary(kvp => kvp.Key,
                kvp => kvp.Value.Errors
                                .Select(e => e.ErrorMessage).ToArray())
                                .Where(m => m.Value.Any());
        }
        return null;
    }
}

And then call that extension method from the Controller action:

if (!ModelState.IsValid)
{
    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}
Rahul Sharma
  • 7,768
  • 2
  • 28
  • 54