Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return ModelState errors to Kendo grid in MVC Web API post method?

I haven't been able to find an example of Kendo + MVC Web API where post/update methods return validation errors. It doesn't look like there is a Kendo extension that could make the following code work.

public HttpResponseMessage Post([ModelBinder(typeof(Prototype.WebApi.ModelBinders.DataSourceRequestModelBinder))][DataSourceRequest] DataSourceRequest request, User user)
    {
        if (this.ModelState.IsValid)
        {               
           //save               
        }
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState.ToDataSourceResult());            
    }

becaue ModelState in this context is System.Web.Http.ModelBinding.ModelStateDictionary and Kendo extensions expect System.Web.Mvc.ModelStateDictionary.

So what is the best way to return ModelState errors from Web API to Kendo?

like image 906
blue Avatar asked Jul 22 '13 14:07

blue


People also ask

How do I get a ModelState error message?

You can use SelectMany function c# to get error message from modelstate mvc. It will generate error message string it contains modelstate errors; we can return as json and display in html element. You have to define validations inside the class as per requirement.

How do I display error message in kendo grid?

Now all you need is a javascript function that is called this and prints the errors such as: function Grid_Error(e){ if(e. errors){ var message = "There are some errors:\n"; // Loop through the errors you defined in the controller $.

How do I find ModelState errors in view?

How to handle error in controller action method and pass error to the View? To pass error to the view we can use ModelState. AddModelError method (if the error is Model field specific) or simply ViewBag or ViewData can also be used.

How does ModelState work in MVC?

In short, the ModelState is a collection of name and value pairs that are submitted to the server during a POST. It also contains error messages about each name-value pair, if any are found. ModelState is a property of a Controller instance, and can be accessed from any class that inherits from Microsoft. AspNetCore.


1 Answers

This works fantastic for us, though we never see ModelState errors and usually omit that part...

Kendo Grid

@model SysMaintViewModel
@(Html.Kendo().Grid<BuildingModel>()
    .Name("BuildingsGrid")
    .Columns(columns =>
    [Stuff Omitted]
    .DataSource(dataSource => dataSource
        .Ajax()
>>>     .Events(e => e.Error("error_handler"))
        .Model(model =>
        {
            model.Id(m => m.Id);
            model.Field(m => m.ProjectId).DefaultValue(Model.ProjectId);
            model.Field(m => m.IsActive).DefaultValue(true);
        })
        .Create(create => create.Action("CreateBuilding", "SysMaint"))
        .Read(read => read.Action("ReadBuildings", "SysMaint", Model))
        .Update(update => update.Action("UpdateBuilding", "SysMaint"))
        .Destroy(destroy => destroy.Action("DestroyBuilding", "SysMaint"))
    )
)

Controller

[HttpPost]
public JsonResult UpdateBuilding([DataSourceRequest]DataSourceRequest request, BuildingModel modelIn)
{
    var building = new BuildingModel();
    if (ModelState.IsValid)
    {
        try
        {
            building = _presentationService.UpdateBuilding(modelIn);
        }
        catch (Exception e)
        {
            ModelState.AddModelError(string.Empty, e.Message);
        }
    }
    else
    {
        var errMsg = ModelState.Values
            .Where(x => x.Errors.Count >= 1)
            .Aggregate("Model State Errors: ", (current, err) => current + err.Errors.Select(x => x.ErrorMessage));
        ModelState.AddModelError(string.Empty, errMsg);
    }
    var buildings = (new List<BuildingModel> {building}).ToDataSourceResult(request, ModelState);
    return Json(buildings, JsonRequestBehavior.AllowGet);
}

UPDATED Controller

We have found this flow to work a bit better and it adds error logging to Elmah (generic example)...

[HttpPost]
public JsonResult Update([DataSourceRequest]DataSourceRequest request, MyObjectModel modelIn)
{
    try
    {
        if (ModelState.IsValid)
        {
            var myObject = _presentationService.Update(modelIn, User.Identity.Name);
            var myObjectList = new List<MyObjectModel> { myObject };
            return Json(myObjectList.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
        }
        else
        {
            var myObjectList = new List<MyObjectModel> { modelIn };
            return Json(myObjectList.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
        }
    }
    catch (Exception e)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(e);
        ModelState.AddModelError(string.Empty, e.Message);
        var myObjectList = new List<MyObjectModel> { modelIn };
        return Json(myObjectList.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
    }
}

Common JavaScript and Kendo Window

@(Html.Kendo().Window()
    .Name("alertWindow")
    .Title("Status Message from Server")
    .Draggable()
    .Resizable()
    .Width(400)
    .Height(200)
    .Modal(true)
    .Visible(false)
)
function showAlertWindow(message) {
    var alertWindow = $('#alertWindow').data('kendoWindow');
    alertWindow.content(message);
    alertWindow.refresh();
    alertWindow.center();
    alertWindow.open();
}
function error_handler(e) {
    if (e.errors) {
        var message = "Errors:\n";
        $.each(e.errors, function (key, value) {
            if ('errors' in value) {
                $.each(value.errors, function () {
                    message += this + "\n";
                });
            }
        });
        showAlertWindow(message);
    }
}

Bonus

Our BaseModel also has an ErrorMessage parameter that we put other types of errors into that checks on page load if the same alert window should be opened for anything else.

$(document).ready(function () {
    if ("@Model.ErrorMessage" != "") {
        showAlertWindow("@Model.ErrorMessage");
    }
});

This has a very nice presentation when an error is thrown - keeps our in-house users from freaking out. I hope this helps you out.

like image 166
Trey Gramann Avatar answered Sep 18 '22 11:09

Trey Gramann