Backend API
        
    @(Html.DevExtreme().DataGrid<DevExtreme.NETCore.Demos.Models.Northwind.Order>()
    .ID("grid")
    .DataSource(d => d.WebApi()
        .Controller("DataGridWebApi")
        .LoadAction("Orders")
        .InsertAction("InsertOrder")
        .UpdateAction("UpdateOrder")
        .DeleteAction("DeleteOrder")
        .Key("OrderID")
        .OnBeforeSend("beforeSend")
    )
    .ShowBorders(true)
    .RepaintChangesOnly(true)
    .Scrolling(s => s.Mode(GridScrollingMode.Virtual))
    .Editing(e => e
        .Mode(GridEditMode.Cell)
        .RefreshMode(GridEditRefreshMode.Reshape)
        .AllowAdding(true)
        .AllowDeleting(true)
        .AllowUpdating(true)
    )
    .Columns(columns => {
        columns.AddFor(m => m.CustomerID)
            .Lookup(lookup => lookup
                .DataSource(d => d.WebApi()
                    .Controller("DataGridWebApi")
                    .LoadAction("CustomersLookup")
                    .LoadMode(DataSourceLoadMode.Raw)
                    .Key("Value")
                    .OnBeforeSend("beforeSend")
                )
                .DataSourceOptions(o => o.Paginate(true))
                .ValueExpr("Value")
                .DisplayExpr("Text")
            );
        columns.AddFor(m => m.OrderDate);
        columns.AddFor(m => m.Freight);
        columns.AddFor(m => m.ShipCountry);
        columns.AddFor(m => m.ShipVia)
            .Lookup(lookup => lookup
                .DataSource(d => d.WebApi()
                    .Controller("DataGridWebApi")
                    .LoadAction("ShippersLookup")
                    .LoadMode(DataSourceLoadMode.Raw)
                    .Key("Value")
                    .OnBeforeSend("beforeSend")
                )
                .ValueExpr("Value")
                .DisplayExpr("Text")
            );
    })
    .Summary(s => s
        .TotalItems(totalItems => {
            totalItems.AddFor(t => t.CustomerID).SummaryType(SummaryType.Count);
            totalItems.AddFor(t => t.Freight).ValueFormat("#0.00").SummaryType(SummaryType.Sum);
        })
    )
)
<div class="options">
    <div class="caption">Options</div>
    <div class="option">
        <span>Refresh Mode:</span>
        @(Html.DevExtreme().SelectBox()
            .ID("refresh-mode")
            .DataSource(new[] { "full", "reshape", "repaint" })
            .InputAttr("aria-label", "Refresh Mode")
            .Value("reshape")
            .OnValueChanged(@<text> function(e) {
                $("#grid").dxDataGrid("instance").option("editing.refreshMode", e.value);
            } </text>)
        )
    </div>
    <div id="requests">
        <div>
            <div class="caption">Network Requests</div>
            @(Html.DevExtreme().Button()
                .ID("clear")
                .Text("Clear")
                .OnClick(@<text> function() {
                    $("#requests ul").empty();
                } </text>)
            )
        </div>
        <ul></ul>
    </div>
</div>
<script>
    function beforeSend(operation, ajaxSettings) {
        var data = ajaxSettings.data || {},
            args = Object.keys(data).map(function (key) {
            return key + "=" + data[key];
        }).join(" ");
        var logList = $("#requests ul"),
            time = DevExpress.localization.formatDate(new Date(), "HH:mm:ss"),
            newItem = $("<li>").text([time, ajaxSettings.method, ajaxSettings.url, args].join(" "));
        logList.prepend(newItem);
    }
</script>
        
        using DevExtreme.NETCore.Demos.Models;
using DevExtreme.NETCore.Demos.Models.DataGrid;
using DevExtreme.NETCore.Demos.Models.SampleData;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace DevExtreme.NETCore.Demos.Controllers {
    public class DataGridController : Controller {
        public ActionResult RemoteCRUDOperations() {
            return View();
        }
    }
}
        
        using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DevExpress.Utils.Serializing.Helpers;
using DevExtreme.NETCore.Demos.Models.DataGrid;
using DevExtreme.NETCore.Demos.Models.Northwind;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DevExtreme.NETCore.Demos.Controllers.ApiControllers {
    [Route("api/[controller]/[action]")]
    public class DataGridWebApiController : Controller {
        InMemoryNorthwindContext _nwind;
        public DataGridWebApiController(NorthwindContext nwind, IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache) {
            _nwind = new InMemoryNorthwindContext(nwind, httpContextAccessor, memoryCache);
        }
        [HttpGet]
        public object Orders(DataSourceLoadOptions loadOptions) {
            return DataSourceLoader.Load(_nwind.Orders, loadOptions);
        }
        [HttpPost]
        public IActionResult InsertOrder(string values) {
            var newOrder = new Order();
            JsonPopulateObjectExtensions.PopulateObject(values, newOrder);
            if(!TryValidateModel(newOrder))
                return BadRequest(ModelState.GetFullErrorMessage());
            _nwind.Orders.Add(newOrder);
            _nwind.SaveChanges();
            return Ok(newOrder);
        }
        [HttpPut]
        public IActionResult UpdateOrder(int key, string values) {
            var order = _nwind.Orders.First(o => o.OrderID == key);
            JsonPopulateObjectExtensions.PopulateObject(values, order);
            if(!TryValidateModel(order))
                return BadRequest(ModelState.GetFullErrorMessage());
            _nwind.SaveChanges();
            return Ok(order);
        }
        [HttpDelete]
        public void DeleteOrder(int key) {
            var order = _nwind.Orders.First(o => o.OrderID == key);
            _nwind.Orders.Remove(order);
            _nwind.SaveChanges();
        }
        // additional actions
        [HttpGet]
        public object OrderDetails(int orderID, DataSourceLoadOptions loadOptions) {
            return DataSourceLoader.Load(
                from i in _nwind.Order_Details
                where i.OrderID == orderID
                select new {
                    Product = i.Product.ProductName,
                    Price = i.UnitPrice,
                    i.Quantity,
                    Sum = i.UnitPrice * i.Quantity
                },
                loadOptions
            );
        }
        [HttpGet]
        public object ShippersLookup(DataSourceLoadOptions loadOptions) {
            var lookup = from i in _nwind.Shippers
                         orderby i.CompanyName
                         select new {
                             Value = i.ShipperID,
                             Text = i.CompanyName
                         };
            return DataSourceLoader.Load(lookup, loadOptions);
        }
        [HttpGet]
        public object CustomersLookup(DataSourceLoadOptions loadOptions) {
            var lookup = from i in _nwind.Customers
                         let text = i.CompanyName + " (" + i.Country + ")"
                         orderby i.CompanyName
                         select new {
                             Value = i.CustomerID,
                             Text = text
                         };
            return DataSourceLoader.Load(lookup, loadOptions);
        }
        [HttpPost]
        public object Batch([FromBody] List<DataChange> changes) {
            foreach(var change in changes) {
                Order order;
                if(change.Type == "update" || change.Type == "remove") {
                    var key = Convert.ToInt32(change.Key);
                    order = _nwind.Orders.First(o => o.OrderID == key);
                } else {
                    order = new Order();
                }
                if(change.Type == "insert" || change.Type == "update") {
                    JsonPopulateObjectExtensions.PopulateObject(change.Data.ToString(), order);
                    if(!TryValidateModel(order))
                        return BadRequest(ModelState.GetFullErrorMessage());
                    if(change.Type == "insert") {
                        _nwind.Orders.Add(order);
                    }
                    change.Data = order;
                } else if(change.Type == "remove") {
                    _nwind.Orders.Remove(order);
                }
            }
            _nwind.SaveChanges();
            return Ok(changes);
        }
    }
}
        
        using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
namespace DevExtreme.NETCore.Demos.Models.Northwind {
    public class InMemoryNorthwindContext : InMemoryDataContext<Order> {
        NorthwindContext _nwind;
        public InMemoryNorthwindContext(NorthwindContext nwind, IHttpContextAccessor contextAccessor, IMemoryCache memoryCache)
            : base(contextAccessor, memoryCache) {
            _nwind = nwind;
        }
        public ICollection<Order> Orders => ItemsInternal;
        public DbSet<Customer> Customers => _nwind.Customers;
        public DbSet<Order_Detail> Order_Details => _nwind.Order_Details;
        public DbSet<Shipper> Shippers => _nwind.Shippers;
        protected override IEnumerable<Order> Source => _nwind.Orders;
        protected override int GetKey(Order item) => item.OrderID;
        protected override void SetKey(Order item, int key) => item.OrderID = key;
    }
}
        
        #grid {
    height: 440px;
}
.options {
    padding: 20px;
    margin-top: 20px;
    background-color: rgba(191, 191, 191, 0.15);
}
.caption {
    margin-bottom: 10px;
    font-weight: 500;
    font-size: 18px;
}
.option {
    margin-bottom: 10px;
}
.option > span {
    position: relative;
    top: 2px;
    margin-right: 10px;
}
.option > .dx-widget {
    display: inline-block;
    vertical-align: middle;
}
#requests .caption {
    float: left;
    padding-top: 7px;
}
#requests > div {
    padding-bottom: 5px;
}
#requests > div:after {
    content: "";
    display: table;
    clear: both;
}
#requests #clear {
    float: right;
}
#requests ul {
    list-style: none;
    max-height: 100px;
    overflow: auto;
    margin: 0;
}
#requests ul li {
    padding: 7px 0;
    border-bottom: 1px solid #dddddd;
}
#requests ul li:last-child {
    border-bottom: none;
}