DEV Community

Cover image for Integrate ASP.NET Core DataGrid With Boilerplate and Perform CRUD Actions
Zahra Sandra Nasaka for Syncfusion, Inc.

Posted on • Originally published at syncfusion.com on

Integrate ASP.NET Core DataGrid With Boilerplate and Perform CRUD Actions

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.

Create an ASP.NET Boilerplate project

Step 1: Install Abp CLI

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
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a new project

In your preferred folder, create a new project with your preferred name using the following command.

abp new SyncfusionGrid -csf
Enter fullscreen mode Exit fullscreen mode

Step 3: Ensure version compatibility

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
Enter fullscreen mode Exit fullscreen mode

Step 4: Configure connection strings

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"
  },
. . .
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Run the project

Run the project. It may take some time to migrate the ABP database to your database.

Run the project

Step 6: Configure XSRF-TOKEN

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");
}
Enter fullscreen mode Exit fullscreen mode

Additionally, in the Index.cshtml file, add the AntiForgeryToken in the razor page as follows.

@Html.AntiForgeryToken()
Enter fullscreen mode Exit fullscreen mode

Step 7: Set the web project as Start-up

Right-click on the [projectname].Web project and select Set as Start-up Project.

Install the Syncfusion ASP.NET Core package

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
Enter fullscreen mode Exit fullscreen mode

[projectname].Web.csproj

[projectname].Web.csproj

Add Syncfusion ASP.NET Core Tag Helper

Open the ~/Pages/_ViewImports.cshtml file and add the Syncfusion.EJ2 TagHelper.

~/Pages/_ViewImports.cshtml

@* add Syncfusion.EJ2 TagHelper. *@
@addTagHelper *, Syncfusion.EJ2
Enter fullscreen mode Exit fullscreen mode

Include stylesheet and script resources

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>
Enter fullscreen mode Exit fullscreen mode

Register Syncfusion Script Manager

Register the script manager <ejs-scripts> at the @section scripts of the Razor page.

~/Pages/Index.cshtml

@section scripts {
    <!-- Syncfusion ASP.NET Core Script Manager -->
    <ejs-scripts></ejs-scripts>
}
Enter fullscreen mode Exit fullscreen mode

Troubleshoot: Render Grid rows without data

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();
});
Enter fullscreen mode Exit fullscreen mode

For more details, refer to the Troubleshooting grid rows without data.

Adding Syncfusion DataGrid

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>
Enter fullscreen mode Exit fullscreen mode

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() }
    ];
}
Enter fullscreen mode Exit fullscreen mode

Handling search operations

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);
}
Enter fullscreen mode Exit fullscreen mode

Handling filtering operations

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);
}
Enter fullscreen mode Exit fullscreen mode

Handling sorting operations

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);
}
Enter fullscreen mode Exit fullscreen mode

Handling paging operations

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);
}
Enter fullscreen mode Exit fullscreen mode

Handling CRUD Operations

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 mapping

CRUD operations within the grid can be mapped to server-side controller actions using the following specific properties:

  • insertUrl: Specifies the URL for inserting new data.
  • removeUrl: Specifies the URL for removing existing data.
  • updateUrl: Specifies the URL for updating existing data.
  • crudUrl: Specifies a single URL for all CRUD operations.
  • batchUrl: Specifies the URL for batch editing.

Insert operation

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
}
Enter fullscreen mode Exit fullscreen mode

Update operation

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
}
Enter fullscreen mode Exit fullscreen mode

Delete operation

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
}
Enter fullscreen mode Exit fullscreen mode

A single method for performing all CRUD operations

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() }];
}
Enter fullscreen mode Exit fullscreen mode

~/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);
}
Enter fullscreen mode Exit fullscreen mode

Handling batch/bulk CRUD operations

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" />
Enter fullscreen mode Exit fullscreen mode

~/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() }];
}
Enter fullscreen mode Exit fullscreen mode

~/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);
}
Enter fullscreen mode Exit fullscreen mode

Refer to the following image.


Integrating ASP.NET Core DataGrid in Boilerplate and performing CRUD actions

GitHub reference

For more details, refer to the integrating ASP.NET Core DataGrid in ASP.NET Boilerplate GitHub demo.

Conclusion

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!

Related blogs

Top comments (0)