This is a migrated thread and some comments may be shown as answers.

Server Side data validation not working

5 Answers 345 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Randy Hompesch
Top achievements
Rank 1
Randy Hompesch asked on 28 Jul 2019, 02:31 PM

Hi,

Ok, so I have a grid, strangely enough called "grid". On it I have .Editable(e => e.Mode(GridEditMode.InCell) set. Everything works great. My data annotations do their job and catch errors. However, one of the columns has a unique index on it. I catch duplicate errors in a try/catch block on the server when they hit save. I add a Model error, but nothing is displayed.
The error message never shows. What am I missing?
Thanks … Ed

@(Html.Kendo().Grid<RoomsModel.RoomModel>()
    .Name("grid")
    .ToolBar(t =>
    {
        t.Create().Text("Add New"); t.Save().Text("Save Changes");
    })
    .HtmlAttributes(new { style = "height: 650px;" })
    .Editable(e => e.Mode(GridEditMode.InCell) //.TemplateName("RoomEditTemplate")
    .Window(w => w.Title("Room").Width(650)))
 
    .Columns(columns =>
     {
         columns.Bound(t => t.Id).Visible(false);
        if (((IEnumerable<Property>)ViewData["Properties"]).Count() > 1)
        {
             columns.ForeignKey(t => t.PropertyId, (System.Collections.IEnumerable)ViewData["Properties"],
             "Id", "PropertyName").Width(125);
        }
        columns.Bound(c => c.RoomNumber).Title("Room Number").Width(125);
        columns.Bound(c => c.RoomName).Title("Room Name").Width(120);
 
                 columns.Command(command =>
         {
             //command.Edit().Text("Edit/View Details");
             command.Destroy();
         }).Width(150);
 
     })
 
    .HtmlAttributes(new { style = "margin-left:3px" })
    .Resizable(resize => resize.Columns(true))
    .Selectable(s => s.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row))
    .Scrollable()
    .Filterable()
    .Sortable()
    .Pageable() //p => { p.PageSizes(true); })
    .DataSource(ds =>
    ds.Ajax()
    .Batch(true)
    .Events(ev => ev.Error("errorHandler"))
    .Read(r => r.Url("?handler=RoomsRead").Data("forgeryToken"))
    .Update(u => u.Url("?handler=RoomsUpdate").Data("forgeryToken"))
    .Create(c => c.Url("?handler=RoomsCreate").Data("forgeryToken"))
    .Model(m =>
    {
        m.Id(t => t.Id);//.Editable(false);
    })
    .PageSize(10)
 
    )
)

 

 

public IActionResult OnPostRoomsCreate([DataSourceRequest] DataSourceRequest request,
   [Bind(Prefix = "models")]IEnumerable<RoomsModel.RoomModel> Rooms)
   {
       Room rm;
 
       List<RoomModel> lstResults = new List<RoomModel>();
       if (ModelState.IsValid)
       {
           try
           {
               using (TransactionScope oScope = new TransactionScope())
               {
                   if (Rooms != null && ModelState.IsValid)
                   {
                       foreach (var r in Rooms)
                       {
                           rm = new Room();
                           rm.RoomName = r.RoomName;
                           .
                           .
                           .
                           _db.Rooms.Add(rm);
                           _db.SaveChanges();
 
                           RoomModel rmm = new RoomModel();
                           rmm.Id = rm.Id;
                           .
                           .
                           .
                           lstResults.Add(rmm);
                       }
                   }
                   oScope.Complete();
               }
           }
            
           catch (Exception ex)
           {
               var sqlException = ex.InnerException as SqlException;
 
               if (sqlException != null && sqlException.Errors.OfType<SqlError>()
                   .Any(se => se.Number == 2601 || se.Number == 2627 /* PK/UKC violation */))
               {
                   StatusMessage = "Error: Room number already used.";
                   ModelState.AddModelError("RoomNumber", StatusMessage);
                   return new JsonResult(new[] { lstResults.ToDataSourceResult(request, ModelState) });
               }
           }
       }
       return new JsonResult(new[] { lstResults.ToDataSourceResult(request, ModelState) });
   }

 

 

5 Answers, 1 is accepted

Sort by
0
Randy Hompesch
Top achievements
Rank 1
answered on 28 Jul 2019, 05:38 PM

Forgot to add:

function errorHandler(e)
{
    debugger;
    if (e.errors)
    {
        var message = "Errors:\n";
        $.each(e.errors, function (key, value)
        {
            if ('errors' in value)
            {
                $.each(value.errors, function ()
                {
                    message += this + "\n";
                });
            }
        });
    alert(message);
    }
}
0
Tsvetomir
Telerik team
answered on 30 Jul 2019, 02:51 PM
Hi Ed,

I have investigated the provided code snippets and it appears that the client-side part has been handled correctly. Can you confirm that the Error event is triggered? It would be triggered only if the server returns an error. If it is not triggered, then, this would mean that the error has not been added to the ModelState on the server-side. 

I suspect that the catch part of the try-catch would be executed only if you make the dedicated check for duplicates and manually throw an exception. Can you ensure that when a duplicate is present, you enter the catch block and return the ModelState with the model itself? 

As well as, this could be observed in the Network tab of the DevTools developer tools of the browser. They would be included in a separate object called Errors in the returned JSON from the server-side.

Let me know on your observations. 


Best regards,
Tsvetomir
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Randy Hompesch
Top achievements
Rank 1
answered on 31 Jul 2019, 07:00 AM

It appears that the issue is with the line:

      return new JsonResult(new[] { lstResults.ToDataSourceResult(request, ModelState) });

seems that if I just return

       return new JsonResult(lstResults.ToDataSourceResult(request, ModelState) );

without the "new []" the error function gets called. Could you explain this?

Also, right now the error function on the client throws an alert. I'd like to make it more consistent and have the tooltip/validator show the error message the same way other data annotation errors work. Basically, I want to through a 

     <div asp-validation-summary="All" class="text-danger"></div>

at the top and have it handle the messages.

Any guidance would be great.

Thanks … Ed

 

0
Accepted
Georgi
Telerik team
answered on 05 Aug 2019, 06:22 AM
Hi Ed,

When the grid is configured for Ajax binding it expects the server to respond with a DataSourceResult object. The ToDataSourceResult method, converts a collection to a DataSourceResult object. Using the below configuration, the server will return a collection with one item which is a DataSourceResult object:

return new JsonResult(new[] { lstResults.ToDataSourceResult(request, ModelState) });

As the grid expects an object - not a collection, it fails to process the response, thus the error event handler is not triggered.

Regarding how to display the message, the Kendo Validator internally uses a Kendo Tooltip. You could create your own tooltip and within the Error event handler display it using the show method.


Regards,
Georgi
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Randy Hompesch
Top achievements
Rank 1
answered on 05 Aug 2019, 09:33 AM

Thanks for the explanation. I now have a good path to follow.

 

Tags
Grid
Asked by
Randy Hompesch
Top achievements
Rank 1
Answers by
Randy Hompesch
Top achievements
Rank 1
Tsvetomir
Telerik team
Georgi
Telerik team
Share this question
or