TL;DR: Learn how to integrate Syncfusion ASP.NET Core DataGrid into an ASP.NET Boilerplate project. This blog walks you through setting up the project, configuring CRUD operations, and adding powerful data functionalities like filtering, sorting, and searching.
ABP (ASP.NET Boilerplate) is an application framework designed to simplify the development of modern web applications. It features a modular architecture and built-in dependency injection, and it supports patterns like Unit of Work and Repository. It includes automatic API generation, multi-tenancy, robust authorization and authentication, and localization support. It also provides auditing, logging, and code generation tools and integrates with popular UI frameworks like Angular, React, and Blazor, offering a foundation for building scalable and maintainable apps.
As the web development landscape evolves, developers constantly seek efficient and feature-rich solutions to enhance their apps. In ASP.NET development, ASP.NET Boilerplate has emerged as a popular framework for building robust and scalable web apps.
In this blog, we’ll learn how to integrate Syncfusion ASP.NET Core DataGrid with ASP.NET Boilerplate framework.
Ensure the Abp CLI is installed globally on your machine. If not, install it using the following command.
dotnet tool install -g Volo.Abp.Cli
In your preferred folder, create a new project with your preferred name using the following command.
abp new SyncfusionGrid -csf
After successfully creating the project, open the solution file. To prevent errors, ensure that the Abp CLI version and all source project versions are the same or lower than the CLI version. If your project Abp package version is higher, update the CLI version by running the following command.
abp cli update --version x.x.x
Configure the appropriate connection strings in the appsettings.json file for both [projectname].Web and [projectname].DbMigration projects. Afterward, right-click on the DbMigration project and select the option, Set as Start-up Project.
[projectname].DbMigration/appsettings.json & [projectname].Web/appsettings.json
{
. . .
"ConnectionStrings": {
"Default": "Server=XXXXX;Database=SyncfusionGrid;Trusted_Connection=True;TrustServerCertificate=True"
},
. . .
}
Run the project. It may take some time to migrate the ABP database to your database.
Since the POST request is used to call the URL method in the index.cs page, we need to configure XSRF-TOKEN and add the following code on the [projectname]WebModule.cs file of the [projectname].Web project.
For more details, refer to the How to Render Grid in ASP.NET Core Razor Page?.
[projectname]WebModule.cs
public override void ConfigureServices(ServiceConfigurationContext context)
{
. . . . . .
// Need to add the codes below.
context.Services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}
Additionally, in the Index.cshtml file, add the AntiForgeryToken in the razor page as follows.
@Html.AntiForgeryToken()
Right-click on the [projectname].Web project and select Set as Start-up Project.
Let’s start by installing the Syncfusion package. Right-click on the [projectname].Web.csproj file, open Manage NuGet Packages, and search for Syncfusion.EJ2.AspNet.Core and then install it.
Alternatively, you can use the Package Manager Console. Ensure that the default project is set to src/[projectname].Web of the ASP.NET Boilerplate framework, and run the following command to install the EJ2 core package:
Install-Package Syncfusion.EJ2.AspNet.Core -Version x.x.x
[projectname].Web.csproj
Open the ~/Pages/_ViewImports.cshtml file and add the Syncfusion.EJ2 TagHelper.
~/Pages/_ViewImports.cshtml
@* add Syncfusion.EJ2 TagHelper. *@
@addTagHelper *, Syncfusion.EJ2
In the ~/Pages/Index.cshtml file, add a link for the EJ2 stylesheet and scripts.
~/Pages/Index.cshtml
<!-- Syncfusion ASP.NET Core controls styles -->
<link rel="stylesheet" href="https://cdn.syncfusion.com/ej2/26.1.40/fluent.css" />
<!-- Syncfusion ASP.NET Core controls scripts -->
<script src="https://cdn.syncfusion.com/ej2/26.1.40/dist/ej2.min.js"></script>
Register the script manager <ejs-script> at the @section scripts of the Razor page.
~/Pages/Index.cshtml
@section scripts {
<!-- Syncfusion ASP.NET Core Script Manager -->
<ejs-scripts></ejs-scripts>
}
By default, ASP.NET Core returns JSON results in camelCase format, which can also alter grid field names. To resolve this issue, we need to add DefaultContractResolver in the Program.cs file.
For this, we need to install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package using the Package Manager Console or NuGet Package Manager.
Program.cs
builder.Services.AddMvc().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
For more details, refer to the Troubleshooting grid rows without data.
Now, insert the following grid code in the ~/Pages/Index.cshtml file. This example links the data using the customAdaptor concept by extending UrlAdaptor. This approach involves sending a post request to retrieve data from the server and execute additional grid actions.
The Syncfusion ASP.NET Core Grid component supports various server-side data operations, such as searching, sorting, filtering, aggregation, and paging. These operations can be managed using the PerformSearching, PerformFiltering, PerformSorting, PerformTake, and PerformSkip methods from the Syncfusion.EJ2.AspNet.Core package. Let’s explore how to manage these data operations using the UrlAdaptor.
In your API service project, add the Syncfusion.EJ2.AspNet.Core package through the NuGet Package Manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution).
To access DataManagerRequest and QueryableOperation, import the Syncfusion.EJ2.Base in your controller page.
~/Pages/Index.cshtml
<ejs-grid id="grid"
load="onLoad"
allowFiltering="true"
allowGrouping="true"
allowSorting="true"
allowPaging="true"
toolbar="@(new List() { 'Add', 'Edit', 'Delete', 'Cancel', 'Update' })">
<e-grid-editsettings allowEditing="true"
allowAdding="true"
allowDeleting="true">
</e-grid-editsettings>
<e-grid-columns>
<e-grid-column field="OrderID"
headerText="Order ID"
isPrimaryKey="true"
textAlign="Right"
width="120">
</e-grid-column>
<e-grid-column field="CustomerID"
headerText="Customer ID"
width="150"
validationRules="@(new { required= true })">
</e-grid-column>
<e-grid-column field="OrderDate"
headerText="Order Date"
width="130"
textAlign="Right"
format="yMd">
</e-grid-column>
<e-grid-column field="Freight"
headerText="Freight"
width="130"
textAlign="Right"
format="C2"
editType="numericedit"
validationRules="@(new { required= true })">
</e-grid-column>
<e-grid-column field="ShipCountry"
headerText="Ship Country"
width="120">
</e-grid-column>
</e-grid-columns>
</ejs-grid>
<abp-script src="/Pages/Index.js"></abp-script>
In the ~/Pages/Index.js file, add the following JavaScript code:
window.customAdaptor = new ej.data.UrlAdaptor();
customAdaptor = ej.base.extend(customAdaptor, {
processResponse: function (data, ds, query, xhr, request, changes) {
request.data = JSON.stringify(data);
return ej.data.UrlAdaptor.prototype.processResponse.call(this, data, ds, query, xhr, request, changes);
}
});
function onLoad() {
this.dataSource = new ej.data.DataManager({
url: '/Index?handler=GridDataOperationHandler',
insertUrl: "/Index?handler=GridInsertPostHandler",
updateUrl: "/Index?handler=GridUpdatePostHandler",
removeUrl: "/Index?handler=GridRemovePostHandler",
adaptor: customAdaptor
});
this.dataSource.dataSource.headers = [
{ 'XSRF-TOKEN': $("input:hidden[name='__RequestVerificationToken']").val() }
];
}
To implement search functionality, ensure your API endpoint supports custom search criteria. Implement the searching logic on the server side using the PerformSearching method from the QueryableOperation class. This allows the custom data source to undergo searching based on the criteria specified in the incoming DataManagerRequest object.
In Pages/Index.cshtml.cs file, you can manage grid data operations like in the following code example.
// All data operations except crud post.
public JsonResult OnPostGridDataOperationHandler([FromBody] DataManagerRequest dm)
{
IEnumerable DataSource = orddata.ToList();
DataOperations operation = new DataOperations();
if (dm.Search != null && dm.Search.Count > 0)
{
DataSource = operation.PerformSearching(DataSource, dm.Search); // Search
}
return dm.RequiresCounts
? new JsonResult(new { result = DataSource, count = count })
: new JsonResult(DataSource);
}
To handle filtering operations, ensure that your API endpoint supports custom filtering criteria. Implement the filtering logic on the server side using the PerformFiltering method from the QueryableOperation class. This allows the custom data source to undergo filtering based on the criteria specified in the incoming DataManagerRequest object.
Pages/Index.cshtml.cs
// All data operations except crud post.
public JsonResult OnPostGridDataOperationHandler([FromBody] DataManagerRequest dm)
{
IEnumerable DataSource = orddata.ToList();
DataOperations operation = new DataOperations();
if (dm.Where != null && dm.Where.Count > 0) // Filtering
{
DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
}
return dm.RequiresCounts
? new JsonResult(new { result = DataSource, count = count })
: new JsonResult(DataSource);
}
For sorting operations, ensure that your API endpoint supports custom sorting criteria. Implement the sorting logic on the server side using the PerformSorting method from the QueryableOperation class. This allows the custom data source to undergo sorting based on the criteria specified in the incoming DataManagerRequest object.
Pages/Index.cshtml.cs
// All data operations except crud post.
public JsonResult OnPostGridDataOperationHandler([FromBody] DataManagerRequest dm)
{
IEnumerable DataSource = orddata.ToList();
DataOperations operation = new DataOperations();
if (dm.Sorted != null && dm.Sorted.Count > 0) // Sorting
{
DataSource = operation.PerformSorting(DataSource, dm.Sorted);
}
int count = DataSource.Cast().Count();
if (dm.Skip != 0)
{
DataSource = operation.PerformSkip(DataSource, dm.Skip); // Paging
}
if (dm.Take != 0)
{
DataSource = operation.PerformTake(DataSource, dm.Take); // Paging
}
return dm.RequiresCounts
? new JsonResult(new { result = DataSource, count = count })
: new JsonResult(DataSource);
}
For paging, ensure that your API endpoint supports custom paging criteria. Implement the paging logic on the server side using the PerformTake and PerformSkip methods from the QueryableOperation class. This allows the custom data source to undergo paging based on the criteria specified in the incoming DataManagerRequest object.
Pages/Index.cshtml.cs
// All data operations except crud post.
public JsonResult OnPostGridDataOperationHandler([FromBody] DataManagerRequest dm)
{
IEnumerable DataSource = orddata.ToList();
DataOperations operation = new DataOperations();
int count = DataSource.Cast().Count();
if (dm.Skip != 0)
{
DataSource = operation.PerformSkip(DataSource, dm.Skip); // Paging
}
if (dm.Take != 0)
{
DataSource = operation.PerformTake(DataSource, dm.Take); // Paging
}
return dm.RequiresCounts
? new JsonResult(new { result = DataSource, count = count })
: new JsonResult(DataSource);
}
The ASP.NET Core DataGrid Component seamlessly integrates CRUD (Create, Read, Update, Delete) operations with server-side controller actions through specific properties: insertUrl, removeUrl, updateUrl, crudUrl, and batchUrl. These properties enable the grid to communicate with the data service for every grid action, facilitating server-side operations.
CRUD operations within the grid can be mapped to server-side controller actions using the following specific properties:
To insert a new record, utilize the insertUrl property to specify the controller action mapping URL for the insert operation.
// normal insert post.
public JsonResult OnPostGridInsertPostHandler([FromBody] CRUDModel value)
{
orddata.Insert(0, value.Value);
return new JsonResult(value);
}
function onLoad() {
this.dataSource = new ej.data.DataManager({
url: '/Index?handler=GridDataOperationHandler',
insertUrl: "/Index?handler=GridInsertPostHandler",
// ... other properties
adaptor: customAdaptor
});
// ... additional code
}
To update existing records, utilize the updateUrl property to specify the controller action mapping URL for the update operation.
// normal update post.
public JsonResult OnPostGridUpdatePostHandler([FromBody] CRUDModel value)
{
var data = orddata.Where(or => or.OrderID == value.Value.OrderID).FirstOrDefault();
if (data != null)
{
data.OrderID = value.Value.OrderID;
data.CustomerID = value.Value.CustomerID;
data.Freight = value.Value.Freight;
data.EmployeeID = value.Value.EmployeeID;
data.ShipCity = value.Value.ShipCity;
data.Verified = value.Value.Verified;
data.OrderDate = value.Value.OrderDate;
data.ShipName = value.Value.ShipName;
data.ShipCountry = value.Value.ShipCountry;
data.ShippedDate = value.Value.ShippedDate;
data.ShipAddress = value.Value.ShipAddress;
}
return new JsonResult(value);
}
function onLoad() {
this.dataSource = new ej.data.DataManager({
// ... other properties
updateUrl: "/Index?handler=GridUpdatePostHandler",
// ... additional code
adaptor: customAdaptor
});
// ... more code
}
To delete existing records, use the removeUrl property to specify the controller action mapping URL for the delete operation
In Pages/Index.cshtml.cs, you can perform grid data operations as follows:
// normal delete post.
public JsonResult OnPostGridRemovePostHandler([FromBody] CRUDModel value)
{
orddata.Remove(orddata.Where(or => or.OrderID == (Int64)value.Key).FirstOrDefault());
return new JsonResult(value);
}
function onLoad() {
this.dataSource = new ej.data.DataManager({
// ... other properties
removeUrl: "/Index?handler=GridRemovePostHandler",
adaptor: customAdaptor
});
// ... additional code
}
Using the crudUrl property, the controller action mapping URL can be specified to perform all the CRUD operations on the server side using a single method instead of defining separate controller action methods for CRUD (insert, update, and delete) operations.
Refer to the following code example.
~/Pages/Index.js
window.customAdaptor = new ej.data.UrlAdaptor();
customAdaptor = ej.base.extend(customAdaptor, {
processResponse: function (data, ds, query, xhr, request, changes) {
request.data = JSON.stringify(data);
return ej.data.UrlAdaptor.prototype.processResponse.call(this, data, ds, query, xhr, request, changes);
}
});
function onLoad() {
this.dataSource = new ej.data.DataManager({
url: '/Index?handler=GridDataOperationHandler',
crudUrl: "/Index?handler=GridCrudPostHandler", // add only crud url here.
adaptor: customAdaptor
});
this.dataSource.dataSource.headers = [{ 'XSRF-TOKEN': $("input:hidden[name='__RequestVerificationToken']").val() }];
}
~/Pages/Index.cshtml.cs
// normal edit crud url post.
public JsonResult OnPostGridCrudPostHandler([FromBody] CRUDModel<OrdersDetails> value)
{
// normal update post.
if (value.Action == "update")
{
var data = orddata.Where(or => or.OrderID == value.Value.OrderID).FirstOrDefault();
if (data != null)
{
data.OrderID = value.Value.OrderID;
data.CustomerID = value.Value.CustomerID;
data.Freight = value.Value.Freight;
data.EmployeeID = value.Value.EmployeeID;
data.ShipCity = value.Value.ShipCity;
data.Verified = value.Value.Verified;
data.OrderDate = value.Value.OrderDate;
data.ShipName = value.Value.ShipName;
data.ShipCountry = value.Value.ShipCountry;
data.ShippedDate = value.Value.ShippedDate;
data.ShipAddress = value.Value.ShipAddress;
}
}
// normal insert post.
else if (value.Action == "insert")
{
orddata.Insert(0, value.Value);
}
// normal delete post.
else if (value.Action == "remove")
{
orddata.Remove(orddata.Where(or => or.OrderID == (Int64)value.Key).FirstOrDefault());
}
return new JsonResult(value);
}
To perform batch operation, define the edit mode as Batch and specify the batchUrl property in the DataManager. Use the add toolbar button to insert a new row in batch editing mode. To edit a cell, double-click the desired cell and update the value as required. To delete a record, select the record and press the delete toolbar button. Now, all CRUD operations will be executed in a single request.
~/Pages/Index.cshtml
<ejs-grid id="grid" load="onLoad" allowFiltering="true" allowGrouping="true" allowSorting="true" allowPaging="true" toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })">
// need to add batch mode.
<e-grid-editsettings allowEditing="true" allowAdding="true" allowDeleting="true" mode="Batch"></e-grid-editsettings>
. . . . . .
</ejs-grid>
<abp-script src="/Pages/Index.js" />
~/Pages/Index.js
// . . . . . . .
function onLoad() {
this.dataSource = new ej.data.DataManager({
url: '/Index?handler=GridDataOperationHandler',
batchUrl: "/Index?handler=GridBatchCrudPostHandler", // add only batch crud url here.
adaptor: customAdaptor
});
this.dataSource.dataSource.headers = [{ 'XSRF-TOKEN': $("input:hidden[name='__RequestVerificationToken']").val() }];
}
~/Pages/Index.cshtml.cs
// Batch edit bulk crud url post.
public JsonResult OnPostGridBatchCrudPostHandler([FromBody] CRUDModel<OrdersDetails> value)
{
if (value.Changed.Count > 0)
{
for (int i = 0; i < value.Changed.Count; i++)
{
var data = orddata.Where(or => or.OrderID == value.Changed[i].OrderID).FirstOrDefault();
if (data != null)
{
data.OrderID = value.Changed[i].OrderID;
data.CustomerID = value.Changed[i].CustomerID;
data.Freight = value.Changed[i].Freight;
data.EmployeeID = value.Changed[i].EmployeeID;
data.ShipCity = value.Changed[i].ShipCity;
data.Verified = value.Changed[i].Verified;
data.OrderDate = value.Changed[i].OrderDate;
data.ShipName = value.Changed[i].ShipName;
data.ShipCountry = value.Changed[i].ShipCountry;
data.ShippedDate = value.Changed[i].ShippedDate;
data.ShipAddress = value.Changed[i].ShipAddress;
}
}
}
if (value.Added.Count > 0)
{
for (var i = 0; i < value.Added.Count; i++)
{
orddata.Insert(i, value.Added[i]);
}
}
if (value.Deleted.Count > 0)
{
for (var i = 0; i < value.Deleted.Count; i++)
{
orddata.Remove(orddata.Where(or => or.OrderID == value.Deleted[i].OrderID).FirstOrDefault());
}
}
return new JsonResult(value);
}
Refer to the following image.
For more details, refer to the integrating ASP.NET Core DataGrid in ASP.NET Boilerplate GitHub demo.
Thanks for reading! In conclusion, integrating Syncfusion ASP.NET Core DataGrid with ASP.NET Boilerplate provides developers with a potent combination for building robust and scalable web apps. By harnessing the capabilities of the DataGrid, developers can streamline their development workflows and deliver compelling user experiences.
Throughout this exploration, we’ve witnessed how our DataGrid serves as a cornerstone for displaying and managing tabular data effectively within ASP.NET Boilerplate apps.
For existing customers, the new version of Essential Studio® is available for download from the License and Downloads page. If you are not a Syncfusion customer, try our 30-day free trial to check out our available features.
You can contact us through our support forum, support portal, or feedback portal. We are here to help you succeed!