Open Closed

Displaying modelstate errors #152


0
nikko created

Hello!

I like to maintain the same feel of client and server validation errors when displaying it to the user. Usually i use the mvc built-in helpers to build the errors for me (ValidationSummary and ValidationFor). When the request gets to the controller if it's a regular post there's no problem we just do:

if (!ModelState.IsValid()) 
{
 return View();
}

And the errors get displayed. The 'problem' starts when we use an AJAX request. Today what i do is read the errors from the ModelState and build a JSON that is returned to the client. Then using jquery i add the errors to the generated html of ValidationSummary and ValidationFor.

I noticed that when a validation error occurs we should use UserFriendlyException. Then i could just implement abp.message.error in the client and it will be done. But the thing is that i can only return one error to the client using this exception. What if i have more errors on my modelstate from multiple properties? Is there anyway to solve this? Also is there a built-in way convert the modelstate errors to this exception?

Thank you for your effort on this project it's really awesome!


4 Answer(s)
  • 0
    hikalkan created
    Support Team

    Hi,

    As I understood, you are building an MVC Action that returns JsonResult. In this methods you wanted to check ModelState and return a result containing validation errors. You can try this:

    You can directly return MvcAjaxResponse (<a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/master/src/Abp.Web.Mvc/Web/Mvc/Models/MvcAjaxResponse.cs">https://github.com/aspnetboilerplate/as ... esponse.cs</a>) like that:

    return Json(new MvcAjaxResponse(...));
    

    MvcAjaxResponse contains Error property that you can use to set validation errors. There is not a built-in method to convert ModelState to MvcAjaxResponse, but you can write an extension method for that (if you then share this extension method, we can add it to ABP).

  • 0
    hikalkan created
    Support Team

    It should be something like that:

    public static class ModelStateExtensions
        {
            public static MvcAjaxResponse ToMvcAjaxResponse(ModelStateDictionary modelState)
            {
                if (modelState.IsValid)
                {
                    return new MvcAjaxResponse();
                }
    
                var validationErrors = new List<ValidationErrorInfo>();
    
                foreach (var state in modelState)
                {
                    foreach (var error in state.Value.Errors)
                    {
                        validationErrors.Add(new ValidationErrorInfo(error.ErrorMessage, state.Key));
                    }
                }
    
                var errorInfo = new ErrorInfo(AbpWebLocalizedMessages.ValidationError)
                                {
                                    ValidationErrors = validationErrors.ToArray()
                                };
    
                return new MvcAjaxResponse(errorInfo);
            }
        }
    

    But I did not tested and checked what it builds. If you can test, please share results.

  • 0
    nikko created

    Hello!

    I've tested it and it kind of works. I modified the code a bit just to compile:

    public static class ModelStateExtensions
        {
            public static MvcAjaxResponse ToMvcAjaxResponse(ModelStateDictionary modelState)
            {
                var validationErrors = new List<ValidationErrorInfo>();
    
                foreach (var state in modelState)
                {
                    foreach (var error in state.Value.Errors)
                    {
                        validationErrors.Add(new ValidationErrorInfo(error.ErrorMessage, new[] { state.Key }));
                    }
                }
    
                var errorInfo = new ErrorInfo("test")
                {
                    ValidationErrors = validationErrors.ToArray()
                };
    
                return new MvcAjaxResponse(errorInfo);
            }
        }
    

    Then i added some modelstate errors like:

    ModelState.AddModelError("Field1", "Field1 Invalid!");
    ModelState.AddModelError("", "Field Withname invalid!");
    

    The JSON that i get back looks like:

    {
      "targetUrl": null,
      "success": false,
      "result": null,
      "error": {
        "code": 0,
        "message": "test",
        "details": null,
        "validationErrors": [
          {
            "message": "Field1 Invalid!",
            "members": [
              "Field1"
            ]
          },
          {
            "message": "Field Withname invalid!",
            "members": [
              ""
            ]
          }
        ]
      },
      "unAuthorizedRequest": false
    }
    

    My question is how do i get validationErrors from the JSON when i need to override abp.message.error:

    abp.message.error = function(message, title) {
        // need to add my code to show the errors the way i want.
    }
    

    Thanks!

  • 0
    hikalkan created
    Support Team

    Thanks for tests and informations. Follow <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/issues/521">https://github.com/aspnetboilerplate/as ... issues/521</a> we can add it to ABP.