Value sent to Controller not as expected for CRUD actions

I am using a URLAdaptor on my grid with individual URL's for Insert, Update and Remove.

I want to get the data passed from the client mapped to my model.

I have tried using the same syntax as used in your examples [FromBody]CRUDModel<model> variable, for instance in another forum thread where you supplied following example:

       
     //insert the record 
     public ActionResult Insert([FromBody]CRUDModel<Employee1Details> value)
     {
          ... 
          //
          Employee1Details.GetAllRecords().Insert(0, value.value);
          return Json(value.value);
     }

My controller method:

     public IActionResult InsertUrl([FromBody]CRUDModel<MdxMemberAttribute> crudmodel)
     {

          MdxMemberAttribute abc = crudmodel.Value;  
          abc.Id = Guid.NewGuid();  // To be replaced by Guid returned from Back End API
          _dbContext.Add(abc);
          _dbContext.SaveChanges();

          crudmodel.Value.Id = abc.Id;
          return Json(crudmodel.Value);
     }

However in this case crudmodel is Null and thus I cannot assign it to abc

I have tried variations like the following:

1. public IActionResult InsertUrl([FromBody]CRUDModel crudmodel)
2. public IActionResult InsertUrl([FromBody]MdxMemberAttribute mdxMemberAttribute)

Only in the first case I get the data from the grid but then I cannot cast it to my model (error: Cannot implicitly convert type 'object' to 'MdxMemberAttribute').

Question 1. Can you let me know how I can cast the data coming from the grid to my model?

Question 2: Before saving the data to the database I need to retrieve the value for the primary key. The grid needs the value for the PK as well. If I use crudmodel.Value.Id = abc.Id and then return crudmodel.Value, will this update the grid correctly? If not, how should this be done?

For completeness I've added my grid definition below:

<div>
    <ejs-grid id="attributeGrid"  toolbar="@(new List<string>() { "Add","Edit", "Delete", "Update", "Cancel", "ExcelExport" })" toolbarClick="toolbarClick" allowExcelExport="true" allowPaging="true" allowSelection="true" allowSorting="true" allowFiltering="true" allowMultiSorting="false" query="new ej.data.Query().addParams('CatalogGuid', '@ViewData["catalogGuid"]').addParams('EntityGuid', '@ViewData["entityGuid"]')">
        <e-data-manager url="/LibMan/AttributeDatasource" adaptor="UrlAdaptor" insertUrl="/LibMan/InsertUrl" updateUrl="/LibMan/UpdateUrl" removeUrl="/LibMan/DeleteUrl" BatchUrl="/LibMan/BatchUrl"></e-data-manager>
        <e-grid-editSettings allowEditing="true" allowAdding="true" allowDeleting="true" mode="Normal" showConfirmDialog="true" allowEditOnDblClick="true"></e-grid-editSettings>
        <e-grid-pagesettings pageCount="5" pageSize="50" pageSizes="@(new string[] { "15", "20", "25", "50", "All" })"></e-grid-pagesettings>
        <e-grid-filterSettings type="Menu" mode="OnEnter" immediateModeDelay="55"></e-grid-filterSettings>
        <e-grid-columns>
            <e-grid-column field="Id" isPrimaryKey="true" visible="false" showInColumnChooser="false"></e-grid-column>
            <e-grid-column field="MdxCatalogGuid" defaultValue="@ViewData["catalogGuid"]" visible="false" showInColumnChooser="false"></e-grid-column>
            <e-grid-column field="MdxEntityGuid" defaultValue="@ViewData["entityGuid"]" visible="false" showInColumnChooser="false"></e-grid-column>
            <e-grid-column field="Name"></e-grid-column>
            <e-grid-column field="MdxAttributeType"></e-grid-column>
            <e-grid-column field="IsMandatory" displayAsCheckBox="true" editType="checkboxedit"></e-grid-column>
            <e-grid-column field="RequiresValidation" displayAsCheckBox="true"></e-grid-column>
            <e-grid-column field="TextLength" format="N0"></e-grid-column>
            <e-grid-column field="NumberDecimals" format="N0"></e-grid-column>
            <e-grid-column field="DateTimeFormat"></e-grid-column>
            <e-grid-column field="LookupEntity"></e-grid-column>
            <e-grid-column field="LookupFilter"></e-grid-column>
            <e-grid-column field="ChangeTrackingEnabled" displayAsCheckBox="true"></e-grid-column>
            <e-grid-column field="ChangeTrackingGroup" format="N0"></e-grid-column>
        </e-grid-columns>
    </ejs-grid>
    <ejs-scripts></ejs-scripts>
</div>

thanks


7 Replies

HJ Hariharan J V Syncfusion Team September 24, 2018 11:15 AM UTC

Hi Ronald, 
 
Thanks for contacting Syncfusion support. 
 
Query: Can you let me know how I can cast the data coming from the grid to my model? 
 
We have validated your query and you can typecast the data based on your model class definition. We have created a sample and using ‘OrderDetails’ for class definition of Grid data. Please find the code example for your reference. 
 
[code example] 
public ActionResult Insert([FromBody]CRUDModel<OrdersDetails> value) 
        { 
 
            OrdersDetails.GetAllRecords().Insert(0, value.value); 
 
            OrdersDetails mobj = value.value; 
            mobj.OrderID = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0); 
            value.value.OrderID = mobj.OrderID; 
            return Json(value.value); 
        } 
... 
public class OrdersDetails 
    { 
        public static List<OrdersDetails> order = new List<OrdersDetails>(); 
        public OrdersDetails() 
            { 
 
            } 
            public OrdersDetails(int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified, DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry, DateTime ShippedDate, string ShipAddress) 
            { 
                ... 
           } 
        public static List<OrdersDetails> GetAllRecords() 
        { 
            ... 
       } 
 
            public int? OrderID { get; set; } 
            ... 
       } 

Note:  We have found that in your code, you defined BatchUrl and insertUrl, updateUrl.   Please find the difference of Grid edit mode. 

  1. When using Normal edit mode of grid editing, we can use insertUrl, updateUrl , removeUrl of UrlAdaptor
  2. When using Batch edit mode of grid editing, we can use batchUrl. Please find the below documentation link for getting more details

                                        https://ej2.syncfusion.com/aspnetcore/documentation/grid/edit.html#batch-url 


Query: Before saving the data to the database I need to retrieve the value for the primary key. The grid needs the value for the PK as well. If I use crudmodel.Value.Id = abc.Id and then return crudmodel.Value, will this update the grid correctly? If not, how should this be done? 
 
Yes, we can change the primary key value of grid before saving data to server. Please find the below code example and sample for your reference. 

[code example] 
public ActionResult Insert([FromBody]CRUDModel<OrdersDetails> value) 
        { 
 
            OrdersDetails.GetAllRecords().Insert(0, value.value); 
 
            OrdersDetails mobj = value.value; 
            mobj.OrderID = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0); 
            value.value.OrderID = mobj.OrderID; 
            return Json(value.value); 
        } 
 
Please find the sample in below link. 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Hariharan 




RD Ronald Dirkx September 24, 2018 02:30 PM UTC

Thanks for your reply. However I think I have another issue with this grid to solve first.
For other testing I have entered some data in the database directly. My datasource Controller method fetches the data from the database correctly but the data isn't shown in the grid.
There are 2 records in the database and the grid renders 2 empty rows. So a correct number of rows with correct number of columns but always with empty values.

This is a sample line of the rendered HTML, I have added full HTML as attachment, you can see a space in aria-label and in ></td>:
<td class="e-rowcell e-detailrowvisible" role="gridcell" tabindex="-1" aria-label=" column header Name" aria-colindex="3" index="0"></td><td class="e-rowcell" role="gridcell" tabindex="-1" aria-label=" column header MdxAttributeType" aria-colindex="4" index="0"></td>


I have added a file that contains the following:
- the rendered HTML captured from Chrome DevTools showing the empty rows
- screenshot of my debugger showing that data is retrieved from the database
- the cshtml file of the PartialView that contains my grid definition


This is my Controller's datasource method:
        public IActionResult AttributeDatasource([FromBody]ExtDataManagerRequest dmr)
        {
            IEnumerable DataSource = _dbContext.MdxMemberAttributes.ToList();
            DataOperations dataOperations = new DataOperations();
            if (dmr.Search != null && dmr.Search.Count > 0)
            {
                DataSource = dataOperations.PerformSearching(DataSource, dmr.Search);  //Search
            }
            if (dmr.Sorted != null && dmr.Sorted.Count > 0) //Sorting
            {
                DataSource = dataOperations.PerformSorting(DataSource, dmr.Sorted);
            }
            if (dmr.Where != null && dmr.Where.Count > 0) //Filtering
            {
                DataSource = dataOperations.PerformFiltering(DataSource, dmr.Where, dmr.Where[0].Operator);
            }
            int count = DataSource.Cast<MdxMemberAttribute>().Count();
            if (dmr.Skip != 0)
            {
                dataOperations.PerformSkip(DataSource, dmr.Skip);
            }
            if (dmr.Take != 0)
            {
                dataOperations.PerformTake(DataSource, dmr.Take);
            }
            var jsonresult = Json(new { result = DataSource, count = count });  // added for debugging, see screenshot
            return dmr.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
        }


I have added the jsonresult for debugging purposes, you can see in the attached screenshot that jsonresult contains 2 records with their values.
And these are the model's classes:
    public class MdxMemberAttribute
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public Guid Id { get; set; }    // will be set by MDS
        public Guid MdxCatalogGuid { get; set; }
        public Guid MdxEntityGuid { get; set; }
        [Required(ErrorMessage ="This field is required")]
        [Display(Name ="Name")]
        public string Name { get; set; }
        // additional mdXone properties
        [Required(ErrorMessage ="This field is required")]
        [Display(Name="Type")]
        public MdxAttributeType MdxAttributeType { get; set; }  // mdXone property
        [Display(Name="Is mandatory")]
        public bool IsMandatory { get; set; }                   // mdXone property
        [Display(Name="Requires validation")]
        public bool RequiresValidation { get; set; }            // mdXone property TODO ?? required?
        // << properties related to the specific Attribute Types
        [Display(Name ="Max. length")]
        public int TextLength { get; set; }
        [Display(Name ="Number of decimals")]
        public int NumberDecimals { get; set; }
        [Display(Name ="Format")]
        public string DateTimeFormat { get; set; }
        [Display(Name ="Lookup from")]
        public string LookupEntity { get; set; }
        [Display(Name ="Lookup filter")]
        public string LookupFilter { get; set; }
        // >> properties related to the specific Attribute Types
        [Display(Name ="Enable change tracking")]
        public bool ChangeTrackingEnabled { get; set; }
        [Display(Name ="Change tracking group")]
        public int ChangeTrackingGroup { get; set; }
        // add multi-language
        public ICollection<MdxCaption> MdxCaptions { get; set; }
    }
    public enum MdxAttributeType
    {
        [Display(Name ="Text")]
        Text,       // Freeform
        [Display(Name ="Number")]
        Number,     // Freeform
        [Display(Name = "Date")]
        DateTime,   // Freeform
        [Display(Name = "True/False")]
        Boolean,    // mdXone property => map to Freeform Number
        [Display(Name = "Link")]
        Link,       // Freeform
        [Display(Name = "Lookup")]
        Lookup,     // Domain-base
        [Display(Name = "File")]
        File        // File
    }
    public class MdxCaption
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "This field is required")]
        [Display(Name ="Attribute")]
        public Guid MdxMemberAttributeId { get; set; }
        [Required(ErrorMessage = "This field is required")]
        [Display(Name = "Language")]
        public string Culture { get; set; }
        [Required(ErrorMessage = "This field is required")]
        [Display(Name = "Caption")]
        public string Caption { get; set; }
        public MdxMemberAttribute MdxMemberAttribute { get; set; }
    }


Hope you can help me, please let me know if you need anything else.
Ronald

Attachment: 003_GridRowsWithoutValues_bb4fcf8a.zip


MS Madhu Sudhanan P Syncfusion Team September 27, 2018 11:50 AM UTC

Hi Ronald, 

Thanks for contacting Syncfusion support. 

Query: There are 2 records in the database and the grid renders 2 empty rows. So a correct number of rows with correct number of columns but always with empty values 

We have analyzed your query and we suspect that it is because of the JSON serialize setting changing the field names to CamelCase. Currently JSON.NET will no longer set ContractResolver to the DefaultContractResolver, but instead it defaults to the CamelCasePropertyNamesContractResolver. So we suggest to use the following code in your Startup.cs file to resolve your problem. 
Code Example: 
[Startup.cs] 
   
public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddMvc(). 
    AddJsonOptions(options => 
    { 
    // JSON serialization not defaulting to default? 
    options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver(); 
    }); 
} 

Please get back to us for further assistance. 

Regards, 
Madhu Sudhanan P 
 



RD Ronald Dirkx September 27, 2018 04:34 PM UTC

Hi,

thanks for your reply.Setting Json.Net to use DefaultContractResolver worked to get the data loaded in the grid, thanks.


However, I am now back to my original issue of this thread. When I add a record in the grid I can't typecast the data to my model class definition.

If I use the following definition for my method public IActionResult AttributeInsert([FromBody]CRUDModel<MdxMemberAttribute> mydata) then mydata is Null. If I use public IActionResult AttributeInsert([FromBody]CRUDModel<MdxMemberAttribute> mydata) then mydata contains data but I cannot typecast it to the model.

There is more information in my original post, otherwise let me know if you need more info.
thanks 
Ronald


MS Madhu Sudhanan P Syncfusion Team September 28, 2018 09:18 AM UTC

Hi Ronald, 

Thanks for your update. 

We have  validated the provided information and checked the reported problem with our end and its working fine at our sample. When we used the generic CRUDModel (CRUDModel<T>) class then it automatically typecast it to the model. 

Please refer to the below code example and sample for more information. 

   public ActionResult Insert([FromBody]CRUDModel<Employee1Details> value) 
        { 
 
            Employee1Details.GetAllRecords().Insert(0, value.value); 
            return Json(value.value); 
        } 
   public class CRUDModel<T> where T : class  //  Generic class 
        { 
            public string action { get; set; } 
 
            public string table { get; set; } 
                        public T value { get; set; } 
            . . . . . 
       } 

 


In your previous update you are facing “ (error: Cannot implicitly convert type 'object' to 'MdxMemberAttribute')” issue. Can you please share the screenshot and more details regarding this. 

Regards, 
Madhu Sudhanan P 



RD Ronald Dirkx September 28, 2018 02:05 PM UTC

Hi,

I have looked at the provided sample solution and I copied the definition of the CRUDModel<T> class into my project.

I then have the following definition for the insertUrl method but crudmodel is Null (see screenshot 1):
public IActionResult AttributeInsert([FromBody]CRUDModel<MdxMemberAttribute> crudmodel)

When I use the following definition for the insertUrl method then crudmodel contains values (see screenshot 2)
public IActionResult AttributeInsert([FromBody]CRUDModel crudmodel)

The error regarding implicit conversion appears with the second defintion of the method but is expected because of the differences in type (I was just trying to get the data defined as by my model), see screenshot 3

Query 1: not sure what is wrong and why I don't receive any data when using CRUDModel<T>
Query 2: is it necessary to have the definition of CRUDModel<T>? I thought it is part of EJ2? If not then you really not to update and include this in your documentation!!

thanks
Ronald

Attachment: 003b_CRUDModel_Null_d33236e2.zip


MS Madhu Sudhanan P Syncfusion Team October 1, 2018 11:50 AM UTC

Hi Ronald, 

We have created a new incident under your account so please follow the incident for further update. Please log on to our support website to check for further updates. 
 

Regards, 
Madhu Sudhanan P 


Loader.
Up arrow icon