From 0e7f9b06040c7e140b7988b6d384029a48bf23bc Mon Sep 17 00:00:00 2001 From: SadhanaBaskaran Date: Tue, 25 Nov 2025 10:57:03 +0530 Subject: [PATCH 1/2] 994264: Updated the UG content and samples for Blazor DataBinding Common folder section --- .../common/data-binding/dapper-databinding.md | 390 +++++++------- .../common/data-binding/grpc-data-binding.md | 338 ++++++++---- .../data-binding/restful-service-binding.md | 487 ++++++++---------- 3 files changed, 661 insertions(+), 554 deletions(-) diff --git a/blazor/common/data-binding/dapper-databinding.md b/blazor/common/data-binding/dapper-databinding.md index 2547a4ab97..146924150a 100644 --- a/blazor/common/data-binding/dapper-databinding.md +++ b/blazor/common/data-binding/dapper-databinding.md @@ -10,180 +10,230 @@ platform: Blazor # How to Bind Data Using Dapper and Perform CRUD Operations -In this section, you can learn how to consume data from a database using [Dapper](https://github.com/DapperLib/Dapper), bind it to a `Syncfusion® Blazor DataGrid` Component, and perform CRUD operations. +The Syncfusion® Blazor [DataGrid](https://blazor.syncfusion.com/documentation/datagrid/getting-started) component supports integration with [Dapper](https://github.com/DapperLib/Dapper) for efficient data access and manipulation. This integration enables binding data from a SQL Server database to the DataGrid and performing **create**, **read**, **update**, and **delete** (**CRUD**) operations with minimal overhead. + +**Dapper** is a lightweight object-relational mapper (**ORM**) that provides high-performance data access by mapping query results to strongly typed models without the complexity of full-featured ORMs. ## Prerequisite software -* Visual Studio 2022. -* MS SQL Server. +The following software components are required to implement data binding with Dapper and Syncfusion® Blazor DataGrid: + +* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/) (latest version with .NET 10 support) +* [.NET 8 or later](https://dotnet.microsoft.com/en-us/download/dotnet) +* [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads) + +Ensure that the development environment is configured with the latest updates for Visual Studio and SQL Server, and install .NET 8.0 or a newer version for compatibility with current features. + +## Creating the Blazor application -## Creating Blazor application +Create a Blazor Web App using Visual Studio 2022 with [Microsoft Blazor templates](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling?view=aspnetcore-10.0&pivots=vs) or the [Syncfusion® Blazor Extension](https://blazor.syncfusion.com/documentation/visual-studio-integration/template-studio) for streamlined project creation. -* Open Visual Studio and follow the steps in the [documentation](https://blazor.syncfusion.com/documentation/getting-started/blazor-server-side-visual-studio) to create the Blazor Server Application. +1. Open **Visual Studio 2022**. +2. Select Create a new project. +3. Choose the **Blazor Web App** template. +4. Configure project options such as **name**, **location**, and **.NET version**. +5. Set [interactive render mode](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-10.0#render-modes) to **Auto**. +6. Define [interactivity location](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling?view=aspnetcore-10.0&pivots=vs#interactivity-location) as **Per page/component** or **Global** based on requirements. + +N> **Recommendation**: Use **Auto** render mode for hybrid interactivity and flexibility. This configuration allows components to switch seamlessly between **server** and **client** rendering.. ## Creating the database -First, create a database named `BugTracker` and a table named `Bugs` to hold the list of bugs. +Create a SQL Server database to store bug tracking information: -1. Open SQL Server 2017 / latest version. -2. Now, create a new database named `BugTracker`. -3. Right-click on the created database and select New Query. -4. Use the following SQL query to create a table named Bugs. +**Launch SQL Server Management Studio (SSMS)** + +1. Open the **Windows Start Menu** and search for **SQL Server Management Studio**. +2. Click the **SSMS icon** to launch the application. +3. In the Connect to Server dialog: + + * **Server type**: Database Engine + * **Server name**: Enter your SQL Server instance name (e.g., localhost or .\SQLEXPRESS). + * **Authentication**: Choose **Windows Authentication** or **SQL Server Authentication**. + +4. Click Connect. + +If SSMS is not installed, download it from [Download SQL Server Management Studio](https://learn.microsoft.com/en-us/ssms/install/install). + +**Create Database and Table** + +1. In **SSMS**, right-click **Databases** in Object Explorer and select **New Database**. +2. Enter **BugTracker** as the database name and click **OK**. +3. Expand the BugTracker database, right-click **Tables**, and select **New Query**. +4. Paste and execute the following SQL script to create the Bugs table: -``` -Create Table Bugs( -Id BigInt Identity(1,1) Primary Key Not Null, -Summary Varchar(400) Not Null, -BugPriority Varchar(100) Not Null, -Assignee Varchar(100), -BugStatus Varchar(100) Not Null) ``` -Now, the table design will look like below. +CREATE TABLE Bugs ( + Id BIGINT IDENTITY(1,1) PRIMARY KEY NOT NULL, + Summary VARCHAR(400) NOT NULL, + BugPriority VARCHAR(100) NOT NULL, + Assignee VARCHAR(100), + BugStatus VARCHAR(100) NOT NULL +); + +``` ![Bug Table Design in Blazor](../images/bug-table-design.png) -## Adding Dapper package and creating a model class +The Bugs table stores details such as **summary**, **priority**, **assignee**, and **status** for each bug record. -To use Dapper and access database in the application, you need to install the following `NuGet` packages. +For SQL Server installation, refer to[ Microsoft SQL Server Downloads](https://www.microsoft.com/en-us/sql-server/sql-server-downloads). -Run the following commands in the Package Manager Console. +## Adding Dapper package and creating the model class -* The following command enable us to use Dapper in our application. +1. **Install Required NuGet Packages** - ``` - Install-Package Dapper -Version 2.1.24 +In the server-side project, install: + +* [Dapper](https://www.nuget.org/packages/Dapper/) – Provides lightweight object mapping for SQL queries. +* [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) – Enables SQL Server connectivity. + +**Options to install**: + + +* **Using NuGet Package Manager in Visual Studio**: - ``` +Navigate to: Tools → NuGet Package Manager → Manage NuGet Packages for Solution. -* The following command provide database access classes such as `SqlConnection`, `SqlCommand`, etc. Also provides data provider for MS SQL Server. +* **Using Package Manager Console**: - ``` +{% tabs %} +{% highlight C# tabtitle="Package Manager" %} + + Install-Package Dapper -Version 2.1.24 Install-Package Microsoft.Data.SqlClient - ``` -Most of the ORMs provide scaffolding options to create model classes. Dapper doesn’t have any in-built scaffolding option. So, you need to create model class manually. Here, you are creating a class named `Bug.cs` in the `Data` folder as follows. +{% endhighlight %} +{% endtabs %} + +The **Microsoft.Data.SqlClient** package provides classes such as **SqlConnection** and **SqlCommand** for database access. + +2. **Creating the Model Class** + +Dapper does not include scaffolding for model generation. Create a model manually to represent the database table. For example, create a class named **Bug.cs** in the **Data** folder: + ```c# -namespace {Your namespace} + +namespace YourNamespace { public class Bug { public int Id { get; set; } - public string Summary { get; set; } - public string BugPriority { get; set; } - public string Assignee { get; set; } - public string BugStatus { get; set; } } } + ``` +This class defines strongly typed properties corresponding to the columns in the **Bugs** table. ![Bug Model Class in Blazor](../images/bug-model-class.png) -## Creating data access layer +## Creating the data access layer -Before creating a data access layer, you need to set the connection string of our database in the `appsettings.json` file as follows. +1. Configure the Connection String + +Add the connection string in **appsettings.json**: ```cshtml + "ConnectionStrings": { - "BugTrackerDatabase": "Server= {Your Server Name};Database=BugTracker;Integrated Security=True" + "BugTrackerDatabase": "Server={Your Server Name};Database=BugTracker;Integrated Security=True" } + ``` ![Connection String in appsettings](../images/connection-string-appsettings.png) -Now, right-click the `Data` folder and select `Class` to create a new class named `BugDataAccessLayer.cs`. Replace this class with the following code, which contains code to handle CRUD in the `Bugs` table. +2. **Create the Data Access Layer Class** -In the following example, +In the **Data** folder, create a class named **BugDataAccessLayer.cs** to handle CRUD operations using **Dapper**. -* In the constructor of the `BugDataAccessLayer`, `IConfiguration` is injected, which helps us to get the connection string provided in the `appsettings.json`. -* `GetBugsAsync` method performs select operation and returns a list of bugs from the Bugs table. -* `AddBugAsync` method inserts a new bug into the Bugs table. -* `UpdateBugAsync` method updates the given bug object in the table. -* `RemoveBugAsync` method removes the given bug by Id. + +3. **Implement CRUD Methods** + +Add the following code in **BugDataAccessLayer.cs**: {% highlight c# %} +p public class BugDataAccessLayer { - public IConfiguration Configuration; - private const string BUGTRACKER_DATABASE = "BugTrackerDatabase"; - private const string SELECT_BUG = "select * from bugs"; + private readonly IConfiguration _configuration; + private const string BugTrackerDatabase = "BugTrackerDatabase"; + private const string SelectBugQuery = "SELECT * FROM Bugs"; + public BugDataAccessLayer(IConfiguration configuration) { - Configuration = configuration; //Inject configuration to access Connection string from appsettings.json. + _configuration = configuration; } public async Task> GetBugsAsync() { - using (IDbConnection db = new SqlConnection(Configuration.GetConnectionString(BUGTRACKER_DATABASE))) - { - db.Open(); - IEnumerable result = await db.QueryAsync(SELECT_BUG); - return result.ToList(); - } + using IDbConnection db = new SqlConnection(_configuration.GetConnectionString(BugTrackerDatabase)); + IEnumerable result = await db.QueryAsync(SelectBugQuery); + return result.ToList(); } public async Task GetBugCountAsync() { - using (IDbConnection db = new SqlConnection(Configuration.GetConnectionString(BUGTRACKER_DATABASE))) - { - db.Open(); - int result = await db.ExecuteScalarAsync("select count(*) from bugs"); - return result; - } + using IDbConnection db = new SqlConnection(_configuration.GetConnectionString(BugTrackerDatabase)); + return await db.ExecuteScalarAsync("SELECT COUNT(*) FROM Bugs"); } public async Task AddBugAsync(Bug bug) { - using (IDbConnection db = new SqlConnection(Configuration.GetConnectionString(BUGTRACKER_DATABASE))) - { - db.Open(); - await db.ExecuteAsync("insert into bugs (Summary, BugPriority, Assignee, BugStatus) values (@Summary, @BugPriority, @Assignee, @BugStatus)", bug); - } + using IDbConnection db = new SqlConnection(_configuration.GetConnectionString(BugTrackerDatabase)); + await db.ExecuteAsync("INSERT INTO Bugs (Summary, BugPriority, Assignee, BugStatus) VALUES (@Summary, @BugPriority, @Assignee, @BugStatus)", bug); } public async Task UpdateBugAsync(Bug bug) { - using (IDbConnection db = new SqlConnection(Configuration.GetConnectionString(BUGTRACKER_DATABASE))) - { - db.Open(); - await db.ExecuteAsync("update bugs set Summary=@Summary, BugPriority=@BugPriority, Assignee=@Assignee, BugStatus=@BugStatus where id=@Id", bug); - } + using IDbConnection db = new SqlConnection(_configuration.GetConnectionString(BugTrackerDatabase)); + await db.ExecuteAsync("UPDATE Bugs SET Summary=@Summary, BugPriority=@BugPriority, Assignee=@Assignee, BugStatus=@BugStatus WHERE Id=@Id", bug); } - public async Task RemoveBugAsync(int bugid) + public async Task RemoveBugAsync(int bugId) { - using (IDbConnection db = new SqlConnection(Configuration.GetConnectionString(BUGTRACKER_DATABASE))) - { - db.Open(); - await db.ExecuteAsync("delete from bugs Where id=@BugId", new { BugId = bugid }); - } + using IDbConnection db = new SqlConnection(_configuration.GetConnectionString(BugTrackerDatabase)); + await db.ExecuteAsync("DELETE FROM Bugs WHERE Id=@BugId", new { BugId = bugId }); } } + {% endhighlight %} -Now, register `BugDataAccessLayer` as scoped service in the `Program.cs` file as follows. +3. Register the Service + +Add the following line in **Program.cs**: + +{% tabs %} +{% highlight c# tabtitle="Program.cs" %} -```cshtml -.... builder.Services.AddScoped(); -``` +{% endhighlight %} +{% endtabs %} ## Adding Syncfusion® Blazor DataGrid component -To add **Blazor DataGrid** component in the app, open the NuGet package manager in Visual Studio (*Tools → NuGet Package Manager → Manage NuGet Packages for Solution*), search and install [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) and [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/). +**Steps**: + +1. **Install Required NuGet Packages** -Alternatively, you can utilize the following package manager command to achieve the same. +* Use **NuGet Package Manager** in Visual Studio or Package Manager Console to install: + + * [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) + * [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/) + +* Package Manager Console commands: {% tabs %} {% highlight C# tabtitle="Package Manager" %} @@ -194,133 +244,119 @@ Install-Package Syncfusion.Blazor.Themes -Version {{ site.releaseversion }} {% endhighlight %} {% endtabs %} -N> Syncfusion® Blazor components are available in [nuget.org](https://www.nuget.org/packages?q=syncfusion.blazor). Refer to [NuGet packages](https://blazor.syncfusion.com/documentation/nuget-packages) topic for available NuGet packages list with component details. +> Syncfusion® Blazor components are available on [nuget.org](https://www.nuget.org/packages?q=syncfusion.blazor). Refer to [NuGet packages](https://blazor.syncfusion.com/documentation/nuget-packages) for a complete list. -Open `_Import.razor` file and add the following namespaces which are required to use the Syncfusion® Blazor DataGrid Component in this application. +2. **Add Required Namespaces** -{% highlight razor %} +Add the required namespaces in **_Imports.razor**: + +{% tabs %} +{% highlight C# tabtitle="_Imports.razor" %} @using Syncfusion.Blazor @using Syncfusion.Blazor.Grids @using Syncfusion.Blazor.Data {% endhighlight %} +{% endtabs %} -Open `Program.cs` file in your application and register the Syncfusion® service. +Register Syncfusion® services in **Program.cs**: -```cshtml +{% tabs %} +{% highlight C# tabtitle="Program.cs" %} -.... using Syncfusion.Blazor; -.... + builder.Services.AddSyncfusionBlazor(); -.... -``` +{% endhighlight %} +{% endtabs %} -Syncfusion® Blazor provides different themes. They are: +3. **Add Theme Stylesheet** -* Bootstrap4 -* Material -* Fabric -* Bootstrap -* High Contrast +Include the Syncfusion theme in the section: -In this demo application, the Bootstrap4 theme will be used. +{% highlight cshtml %} -* For **.NET 7** app, add theme in the `` of the **~/Pages/_Host.cshtml** file. + -* For **.NET 6** app, add theme in the `` of the **~/Pages/_Layout.cshtml** file. +{% endhighlight %} +Add this stylesheet in the following locations based on the project type: -{% highlight cshtml %} - - .... - - +* **Blazor Web App**: **~/Components/App.razor** +* **Blazor WebAssembly**: **wwwroot/index.html** +* **Blazor Server**: **~/Pages/_Host.cshtml** -{% endhighlight %} +4. **Add Script Reference** -Also, include the script reference in the following files +Include the Syncfusion script at the end of the : -* For **.NET 7** app, add script reference at end of the `` section of the **~/Pages/_Host.cshtml** file. +{% highlight cshtml %} -* For **.NET 6** app, add script reference at end of the `` section of the **~/Pages/_Layout.cshtml** file. + -{% highlight cshtml %} - - .... - - {% endhighlight %} -In previous steps, you have successfully configured the Syncfusion® Blazor package in the application. Now, you can add the DataGrid Component to the `index.razor` page of your app. +5. **Add DataGrid Component** -{% highlight cshtml %} +Insert the [DataGrid](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html) component in **Index.razor**: +{% tabs %} +{% highlight razor %} - + {% endhighlight %} +{% endtabs %} ## Binding data to the DataGrid component -Now, get SQL data using Dapper and bind it to the DataGrid component. To bind the database table to Syncfusion® Blazor DataGrid, use the [custom data binding feature](https://blazor.syncfusion.com/documentation/datagrid/custom-binding) here. - -The following points must be considered for creating a custom adaptor. +To bind SQL Server data retrieved via Dapper to the Syncfusion® Blazor DataGrid, implement a custom data adaptor. -* Our custom adaptor must extend the `DataAdaptor` class. -* Override available CRUD methods to handle data querying and manipulation. -* Register our custom adaptor class as a service in the `Program.cs`. +1. **Create a Custom Adaptor Class** -Now, create a new class named `BugDataAdaptor.cs` under the `Data` folder and replace the following code in that class. - -In the following code example, - -* Extended `BugDataAdaptor` class with `DataAdaptor` base class. -* Injected `BugDataAccessLayer` instance to perform data operations. +In the **Data** folder, create a class named **BugDataAdaptor.cs** and extend the **DataAdaptor** base class: {% highlight c# %} -public class BugDataAdaptor: DataAdaptor + +public class BugDataAdaptor : DataAdaptor { - private BugDataAccessLayer _dataLayer; - public BugDataAdaptor(BugDataAccessLayer bugDataAccessLayer) + private readonly BugDataAccessLayer _dataLayer; + + public BugDataAdaptor(BugDataAccessLayer dataLayer) { - _dataLayer = bugDataAccessLayer; + _dataLayer = dataLayer; } - public override async Task ReadAsync(DataManagerRequest dataManagerRequest, string key = null) + public override async Task ReadAsync(DataManagerRequest request, string key = null) { List bugs = await _dataLayer.GetBugsAsync(); int count = await _dataLayer.GetBugCountAsync(); - return dataManagerRequest.RequiresCounts ? new DataResult() { Result = bugs, Count = count } : (object)bugs; + return request.RequiresCounts ? new DataResult { Result = bugs, Count = count } : (object)bugs; } } + {% endhighlight %} -Now, Open the `Program.cs` file in the application and register the `BugDataAdaptor` class. +2. **Register the Custom Adaptor** + +In **Program.cs**, register the adaptor as a scoped service: {% tabs %} {% highlight c# tabtitle="~/Program.cs" hl_lines="4"%} -.... -builder.Services.AddScoped(); -builder.Services.AddSyncfusionBlazor(); builder.Services.AddScoped(); -..... {% endhighlight %} {% endtabs %} -Now, you need to add the `SfDataManager` in Grid for binding the data to the Grid and added column definition. - -In the following code example, +3. **Add SfDataManager in the Grid** -* Defined `SfDataManager` component to provide data source to the grid. You can see that we have specified the `AdaptorInstance` property with the type of the custom adaptor we created in the previous step and mentioned the `Adaptor` property as `Adaptors.CustomAdaptor`. +In **Index.razor**, configure the DataGrid to use the custom adaptor: -* `TValue` is specified as `Bug` class. {% highlight razor %} @@ -330,7 +366,9 @@ In the following code example, {% endhighlight %} -Grid columns can be defined using the [GridColumn](https://blazor.syncfusion.com/documentation/datagrid/columns) component. Next, you can create columns using the following code. Let's explore the properties used and their applications. +4. **Define Grid Columns** + +Configure columns using the [GridColumn](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html) component: {% highlight razor %} @@ -338,28 +376,24 @@ Grid columns can be defined using the [GridColumn](https://blazor.syncfusion.com - - - - + + + + {% endhighlight %} -Now, the DataGrid will look like this while running the application. The displayed records are fetched from the database. - ![Bug Grid Data in Blazor](../images/bug-grid-data.png) -## Handling CRUD operations with our Syncfusion® Blazor DataGrid component - -You can enable editing in the grid component using the [GridEditSettings](https://blazor.syncfusion.com/documentation/datagrid/editing) component. Grid provides various modes of editing options such as Inline/Normal, Dialog, and Batch editing. Refer to the following documentation for your reference. +## Handling CRUD operations in the DataGrid -[Grid Editing in Blazor](https://blazor.syncfusion.com/documentation/datagrid/editing#editing) +Enable [editing](https://blazor.syncfusion.com/documentation/datagrid/editing) in the Syncfusion® Blazor DataGrid using the [GridEditSettings](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridEditSettings.html) component and implement CRUD logic in the custom adaptor. -N> Normal editing is the default edit mode for the DataGrid component. You need to set the IsPrimaryKey property of Column as True for a particular column, whose value is a unique value for editing purposes. +**Enable Editing** -Here, we are using inline edit mode and the [Toolbar](https://blazor.syncfusion.com/documentation/datagrid/tool-bar) property to show toolbar items for editing. +Configure editing in the grid using `GridEditSettings`. The grid supports multiple editing modes such as [Inline](https://blazor.syncfusion.com/documentation/datagrid/in-line-editing), [Dialog](https://blazor.syncfusion.com/documentation/datagrid/dialog-editing), and [Batch](https://blazor.syncfusion.com/documentation/datagrid/batch-editing). The example below uses Inline mode with the [Toolbar](https://blazor.syncfusion.com/documentation/datagrid/tool-bar) property to show toolbar items for editing. {% highlight razor %} @@ -368,20 +402,20 @@ Here, we are using inline edit mode and the [Toolbar](https://blazor.syncfusion. - - - - + + + + {% endhighlight %} -You have already created CRUD operations methods in the data access layer section itself. Now, you are going to call those methods while performing CRUD actions in DataGrid. +## Insert a record -## Insert a row +When the **Add** button is clicked and the form is submitted, the **InsertAsync** method is executed. This method inserts a new bug record into the database: -Add the following codes(`InsertAsync`) in the `BugDataAdaptor`(CustomAdaptor) class to perform insert operation. +![Insert a row in Grid](../images/insert-a-row.png) {% highlight c# %} @@ -393,17 +427,13 @@ public override async Task InsertAsync(DataManager dataManager, object d {% endhighlight %} -To insert a new row, click the `Add` toolbar button. The new record edit form will look like below. - -![Insert a row in Grid](../images/insert-a-row.png) - -Clicking the `Update` toolbar button will call the `InsertAsync` method of our `BugDataAdaptor` to insert the record in the `Bug` table. Now, the successfully inserted record in the grid will look like below. - ![After inserting a row in Grid](../images/after-inserting-a-row.png) -## Update a row +## Update a record + +When the **Edit** button is used and changes are saved, the **UpdateAsync** method updates the selected bug record: -Add the following codes (`UpdateAsync`) in the `BugDataAdaptor`(CustomAdaptor) class to perform update operation. +![Updating a row in Grid](../images/updating-a-row.png) {% highlight c# %} @@ -415,17 +445,11 @@ public override async Task UpdateAsync(DataManager dataManager, object d {% endhighlight %} -To edit a row, select any row and click the `Edit` toolbar button. The edit form will look like below. - -![Updating a row in Grid](../images/updating-a-row.png) - -Here, the `Status` field value is changed from `Not started` to `In progress`. Clicking the `Update` toolbar button will call the `UpdateAsync` method of `BugDataAdaptor` to update the record in the `Bug` table. Now, the successfully updated record in the grid will look like below. - ![After updating a row in Grid](../images/after-updating.png) ## Delete a row -Add the following codes(`RemoveAsync`) in the `BugDataAdaptor`(CustomAdaptor) class to perform update operation. +When the **Delete** button is clicked, the **RemoveAsync** method deletes the selected bug record by its primary key: {% highlight c# %} @@ -437,10 +461,10 @@ public override async Task RemoveAsync(DataManager dataManager, object p {% endhighlight %} -To delete a row, select any row and click the `Delete` toolbar button. Clicking the `Delete` toolbar button will call the `RemoveAsync` method of our `BugDataAdaptor` to update the record in the `Bug` table. - -N> Find the sample from this [Github](https://github.com/SyncfusionExamples/blazor-datagrid-dapper-crud) location. +N> Find the sample at this [GitHub repository](https://github.com/SyncfusionExamples/blazor-datagrid-dapper-crud). ## See also * [Create Blazor CRUD Application with PostgreSQL and Dapper](https://www.syncfusion.com/blogs/post/create-blazor-crud-application-with-postgresql-and-dapper.aspx) +* [Syncfusion® Blazor DataGrid Documentation](https://blazor.syncfusion.com/documentation/datagrid/getting-started) +* [Custom Data Binding in Blazor DataGrid](https://blazor.syncfusion.com/documentation/datagrid/connecting-to-adaptors/custom-adaptor) diff --git a/blazor/common/data-binding/grpc-data-binding.md b/blazor/common/data-binding/grpc-data-binding.md index f43bfee7a2..689df4ec21 100644 --- a/blazor/common/data-binding/grpc-data-binding.md +++ b/blazor/common/data-binding/grpc-data-binding.md @@ -9,59 +9,97 @@ documentation: ug # Bind Data to the Syncfusion® Blazor Components Using gRPC Service -In this topic, you can learn how to consume data from [gRPC](https://grpc.io/) service and bind it to a Syncfusion® Blazor Component. +## Introduction + +This section describes how to consume data from a [gRPC](https://grpc.io/) service and bind it to Syncfusion® Blazor components. The approach leverages gRPC for efficient communication between the client and server in Blazor applications, enabling high-performance data transfer compared to traditional REST services. + +**What is gRPC?** + +**gRPC** (gRPC Remote Procedure Call) is an open-source framework developed by Google for high-performance communication between distributed systems. It uses HTTP/2 for transport and Protocol Buffers for message serialization, making it faster and more efficient than JSON-based REST APIs. **gRPC** allows client applications to invoke server methods as if they were local, supports multiple programming languages, and provides features such as streaming and strong typing. ## Prerequisite software -The following software are needed, +The following software must be installed before configuring gRPC with Syncfusion® Blazor components: -* Visual Studio 2022. -* .NET 8.0 or later. +* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/) (latest version with .NET 10 support) +* [.NET 8 or later](https://dotnet.microsoft.com/en-us/download/dotnet) ## Creating Blazor webassembly application -You can create a **Blazor WebAssembly App** with **ASP.NET Core Hosted** using Visual Studio via [Microsoft Templates](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling?view=aspnetcore-7.0) +Create a **Blazor WebAssembly App** with **ASP.NET Core Hosted** using **Visual Studio**. This configuration enables the client-side Blazor application to communicate with the server through gRPC services. -Finally, ensure to select the **ASP.NET Core Hosted** application. +To create the application: + +* Open **Visual Studio** and select **Blazor WebAssembly Standalone App** from the project templates. +* Enable the **ASP.NET Core Hosted** option during project creation. ![Create hosted application in Blazor](../images/create-hosted-application.png) +N> The **ASP.NET Core Hosted** option is required because gRPC services run on the server and must be accessible to the client application. + ## Adding gRPC dependencies -You need to install the following dependencies on your **Client**, **Server**, and **Shared** projects. +Install the required NuGet packages in the **Shared**, **Server**, and **Client** projects to enable gRPC communication. + +* **Shared Project** + +* [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf) – Provides Protocol Buffers serialization. +* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client/) – Enables gRPC client functionality. +* [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) – Generates strongly typed classes from .proto files. + +* **Server Project** + +* [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCore/) – Adds gRPC server support. +* [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web/) – Enables gRPC-Web for browser-based clients. -Starting with the **Shared project**, **Right-click** the project and go to **Manage NuGet packages**. Browse for and install the following packages in the **Shared** project: +* **Client Project** -* [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf) -* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client/) -* [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) +* [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web/) – Provides gRPC-Web client support. -Next, follow the same process and go to your **Server** project to install these packages: +**Options to Install** -* [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCore/) -* [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web/) +* Using NuGet Package Manager in Visual Studio -Then, go to your **Client** project and install the following package: + * Navigate to: Tools → NuGet Package Manager → Manage NuGet Packages for Solution -* [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web/) +Select the appropriate project and install the packages listed above. -## Add proto file and service to the project +* **Using Package Manager Console** -gRPC works with Proto files which are written in protocol buffer language that define your messaging. To learn more about the language, visit this [guide](https://developers.google.com/protocol-buffers/docs/proto3#simple). +{% tabs %} +{% highlight C# tabtitle="Package Manager" %} -To add a proto file, **Right-click** the **Shared** project, go to **Add**, and then select **New item**. You can choose a Class file and name it as `order.proto` and select **Add**. +Install-Package Google.Protobuf -ProjectName Shared +Install-Package Grpc.Net.Client -ProjectName Shared +Install-Package Grpc.Tools -ProjectName Shared +Install-Package Grpc.AspNetCore -ProjectName Server +Install-Package Grpc.AspNetCore.Web -ProjectName Server +Install-Package Grpc.Net.Client.Web -ProjectName Client -Remove the boiler plate code in the file. Copy the following code and paste it into your proto file. +{% endhighlight %} +{% endtabs %} -```c# +## Add proto file and service +Proto files are written in the Protocol Buffers language and define the structure of messages and services for gRPC. For detailed syntax and examples, refer to the [Protocol Buffers guide](https://developers.google.com/protocol-buffers/docs/proto3#simple). + +1. **Add the .proto File** + +Create a Protocol Buffers file to define the **gRPC service** and message structure. +Steps: + +1. In the **Shared** project, right-click and select **Add → New Item**. +2. Add a new file named **order.proto**. +3. Replace the default content with the following: + +{% tabs %} +{% highlight proto tabtitle="order.proto" %} syntax = "proto3"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; option csharp_namespace = "BlazorAPPgRPC.Shared"; - package Orders; service OrdersService { @@ -69,7 +107,7 @@ service OrdersService { } message OrdersResponse { - repeated Orders = 1; + repeated Orders orders = 1; } message Orders { @@ -79,17 +117,22 @@ message Orders { string ShipCountry = 4; string ShipCity = 5; } -``` +{% endhighlight %} +{% endtabs %} -Go to the proto file `properties` and select the `Protobuf` compiler as the **Build Action**. Then, select the `Client and Server option` as the `gRPC Stub Classes`. Refer to the following screenshot. +**Configure Build Action**: + +* Set **Build Action** to **Protobuf Compiler**. +* Select **Client** and **Server** for gRPC Stub Classes. ![Proto file properties in Blazor](../images/proto-file-properties.png) -## Adding Orders Service +2. **Add Partial Class for Orders** -Now, add `Orders` partial class in the **Shared** project. The main properties of this class are generated from the `.proto` file. However, you can also add some extra useful properties to this partial class. +Extend the generated **Orders** class in the **Shared** project with an additional property for easier date handling: -```c# +{% tabs %} +{% highlight C# tabtitle="Orders.cs" %} using Google.Protobuf.WellKnownTypes; using System; @@ -100,38 +143,38 @@ namespace BlazorAPPgRPC.Shared public DateTime OrderDate { get => DateTimeStamp.ToDateTime(); - set { DateTimeStamp = Timestamp.FromDateTime(value.ToUniversalTime()); } + set => DateTimeStamp = Timestamp.FromDateTime(value.ToUniversalTime()); } } } -``` -Create **Services folder** in the **Server** project and add **OrdersService** file in that folder. Then, copy the following code and paste it into your service file or create your own service logic. +{% endhighlight %} +{% endtabs %} + +3. **Implement the gRPC Service** -```c# -public class OrdersService : BlazorAPPgRPC.Shared.OrdersService.OrdersServiceBase +Create a **Services** folder in the **Server** project and add **OrdersService.cs** to implement the gRPC service logic: + +{% tabs %} +{% highlight C# tabtitle="OrdersService.cs" %} +using BlazorAPPgRPC.Shared; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; + +public class OrdersService : OrdersServiceBase { - private static readonly string[] Countries = new[] - { - "Berlin", "Tokyo", "Denmark", "Tokyo", "Olso" - }; - private static readonly string[] Names = new[] - { - "VINET", "RIO", "RAJ", "MAH", "RAM" - }; - private static readonly string[] Cities = new[] - { - "New York", "London", "Hue" - }; + private static readonly string[] Countries = { "Berlin", "Tokyo", "Denmark", "Oslo" }; + private static readonly string[] Names = { "VINET", "RIO", "RAJ", "MAH", "RAM" }; + private static readonly string[] Cities = { "New York", "London", "Hue" }; + public override Task GetOrders(Empty request, ServerCallContext context) { var response = new OrdersResponse(); - response.Orders.AddRange(GetOrders()); - - return Task.FromResult(response); + return Task.FromResult(response); } - public IEnumerable GetOrders() + + private IEnumerable GetOrders() { var rng = new Random(); return Enumerable.Range(1, 365).Select(index => new Orders @@ -144,87 +187,123 @@ public class OrdersService : BlazorAPPgRPC.Shared.OrdersService.OrdersServiceBas }); } } -``` -N> The **OrdersService** class is inherited from **BlazorAPPgRPC.Shared.OrdersService.OrdersServiceBase**, which is generated automatically from the `.proto` file. +{% endhighlight %} +{% endtabs %} + +N> The **OrdersService** class inherits from **OrdersServiceBase**, which is generated from the **.proto** file. -## Configure gRPC and gRPC-Web in the server +## Configure gRPC and gRPC-Web -You need to register the **gRPC service** in your `Startup.cs` file. This enables you to use dependency injection to consume the service across the app. Add the following code to your `ConfigureServices` method in the **Server Startup.cs** file: +To enable communication between the Blazor WebAssembly client and the server using gRPC-Web, configure both the **Server** and **Client** projects. -```c# +1. **Server Configuration** + +* **Register gRPC Services** + +Add the gRPC service and required dependencies in the **ConfigureServices** method of **Startup.cs**: + +{% tabs %} +{% highlight C# tabtitle="Startup.cs" %} public void ConfigureServices(IServiceCollection services) { services.AddScoped(); services.AddGrpc(); - . . . + // Other service registrations } -``` +{% endhighlight %} +{% endtabs %} + +* **Enable gRPC-Web Middleware** -Then, add the gRPC-Web middleware to the apps configuration and register the gRPC service. This must be added after UseRouting and before UseEndpoints in the `Configure` method. +Add the gRPC-Web middleware in the **Configure** method. This must be placed **after UseRouting** and **before UseEndpoints**: -```c# +{% highlight csharp %} public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - . . . app.UseRouting(); app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); app.UseEndpoints(endpoints => { endpoints.MapGrpcService(); - . . . + // Other endpoints }); } -``` +{% endhighlight %} -In the **Client** project, add the **OrdersService** to the container, then create a gRPC-Web channel pointing to the back-end server and instantiate the gRPC clients for this channel. Refer to the following code to modify the `Program.cs` file. +2. **Client Configuration** -```c# +In the Client project, create a gRPC-Web channel and register the gRPC client in **Program.cs**:` + +{% tabs %} +{% highlight C# tabtitle="Program.cs" %} using Grpc.Net.Client; using Grpc.Net.Client.Web; using Microsoft.AspNetCore.Components; -. . . + public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); - . . . + builder.Services.AddSingleton(services => { var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler())); var backendUrl = services.GetRequiredService().BaseUri; var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient }); - return new OrdersService.OrdersServiceClient(channel); }); + + await builder.Build().RunAsync(); } -``` +{% endhighlight %} +{% endtabs %} + +N> The **OrdersService.OrdersServiceClient** class is generated automatically from the **.proto** file. + +## Add Syncfusion® Blazor DataGrid + +The Syncfusion® Blazor DataGrid component will be used to display data retrieved from the gRPC service. + +1. **Install Syncfusion NuGet Package** + +Install the required NuGet package in the Client project: + +* [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) +* [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/) + +**Options to install**: + +* **Using NuGet Package Manager** -N> The **OrdersService.OrdersServiceClient** class is also generated automatically from the `.proto` file. + Navigate to: **Tools → NuGet Package Manager → Manage NuGet Packages for Solution** -## Add Syncfusion® Blazor DataGrid package + Select the Client project and install above packages. -We are going to explain this data (gRPC service data) binding process using the Syncfusion® DataGrid component. So, we are going to install the packages required to use the Syncfusion® Blazor components. Now, right-click **Dependencies** in the project and select **Manage NuGet Packages**. +* **Using Package Manager Console** -![Manage NuGet packages](../images/manage-nuget-pack.png) + {% tabs %} + {% highlight C# tabtitle="Package Manager Console" %} -In the **Browse** tab, search and install the `Syncfusion.Blazor.Grid` NuGet package. + Install-Package Syncfusion.Blazor.Grid -ProjectName Client -![Manage NuGet packages](../images/browse-nuget.png) + {% endhighlight %} + {% endtabs %} -N> For this demo, `Syncfusion.Blazor`(19.1.0.66) NuGet package is used. A new `Syncfusion.Blazor` NuGet package with new enhancement will be released in our every-week release and main release. So, you can check and update to the [latest versions](https://www.nuget.org/packages/Syncfusion.Blazor). +2. **Register Syncfusion Services** -## Adding Syncfusion® Blazor DataGrid component +Add the required namespaces in **_Imports.razor**: -Open `_Import.razor` file and add the following namespaces which are required to use Syncfusion® Blazor DataGrid Component in this application. +{% highlight razor %} -```cshtml @using Syncfusion.Blazor @using Syncfusion.Blazor.Grids -``` -Open `Program.cs` file in a **Client** project and **register** the `Syncfusion® service` in the **ConfigureServices** method as follows. +{% endhighlight %} -```c# +Register Syncfusion® services in **Program.cs**: + +{% tabs %} +{% highlight C# tabtitle="Program.cs" %} using Syncfusion.Blazor; namespace BlazorAPPgRPC.Client @@ -236,46 +315,77 @@ namespace BlazorAPPgRPC.Client var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add("#app"); builder.Services.AddSyncfusionBlazor(); - . . . + await builder.Build().RunAsync(); } } } -``` -In this demo application, the **Bootstrap4** theme will be used. To add the theme, open `~/wwwroot/index.html` file and add the following CSS reference code. +{% endhighlight %} +{% endtabs %} + +3. **Apply Theme stylesheet** + +Include the Syncfusion theme in **wwwroot/index.html**: + +{% highlight cshtml %} + + + +{% endhighlight %} + +Add this stylesheet in the following locations based on the project type: + +* **Blazor Web App**: **~/Components/App.razor** +* **Blazor WebAssembly**: **wwwroot/index.html** +* **Blazor Server**: **~/Pages/_Host.cshtml** -```html - -``` +4. **Add Script Reference** -In previous steps, we have successfully configured the Syncfusion® Blazor package in the application. Now, we can add the DataGrid Component to the `Index.razor`. +Include the Syncfusion script at the end of the : -```cshtml +{% highlight cshtml %} + + + +{% endhighlight %} + +5. **Add DataGrid Component** + +Insert the [DataGrid](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html) component in **Index.razor**: + +{% tabs %} +{% highlight razor %} -``` +{% endhighlight %} +{% endtabs %} ## Bind data to Blazor DataGrid component -To consume data from the gRPC service, inject the **OrdersServiceClient** into the razor page and assign it to the DataGrid’s `DataSource` property. +To display data from the gRPC service in the Syncfusion® Blazor DataGrid: -Here, the `DataSource` property of the DataGrid component is used to bind the data to DataGrid in the WebAssembly application. +1. **Inject the gRPC Client** -Grid columns can be defined using the [GridColumn](https://blazor.syncfusion.com/documentation/datagrid/columns/) component. Columns are created using the following code, let’s see the properties used and their usage. +Add the **OrdersServiceClient** to the Razor page: -* `Field` property specifies the column name of the **Orders** table to display in the grid column. -* The `Width` property specifies the column width. -* `Format` property helps to format number, currencies, and date in a particular culture. Here, the **OrderDate** column has been formatted. -* `HeaderText` property specifies the column header name. +{% tabs %} +{% highlight razor %} -```cshtml @inject OrdersService.OrdersServiceClient OrdersServiceClient @using BlazorAPPgRPC.Shared @using Google.Protobuf.WellKnownTypes -

Orders

+{% endhighlight %} +{% endtabs %} + +2. **Define the Grid Layout** +Configure the DataGrid with columns mapped to the Orders model: + +{% tabs %} +{% highlight razor %} +

Orders

This component demonstrates fetching data from the gRPC service.

@if (orders == null) @@ -288,7 +398,7 @@ else - + @@ -296,7 +406,6 @@ else } @code { - private IList orders; protected override async Task OnInitializedAsync() @@ -304,20 +413,33 @@ else orders = (await OrdersServiceClient.GetOrdersAsync(new Empty())).Orders; } } -``` - -Now, the DataGrid will look like this while running the application. The displayed records are fetched from the gRPC service. +{% endhighlight %} +{% endtabs %} ![Binding data from gRPC service in Blazor](../images/binding-data-from-grpc-service.png) -After rendering the Grid with data, you can verify that we are using the gRPC-Web service by using the following way. Open **Network** Tab and reload the index page. +3. **Verify gRPC Communication** -The **Orders** data will be loaded, and you will see the name of the method **GetOrders**. Click on the **GetOrders** name to view the Response Headers which show the **content-type** being **application/grpc-web**. +After running the application, open the **Network tab** in browser developer tools. Reload the page and check the **GetOrders** request. The response headers should include **content-type: application/grpc-web**, confirming gRPC-Web is used. ![Checking gRPC in Blazor](../images/grpc-check.png) -In the ``Index.razor`` page, **Grid with gRPC service** has been rendered, and in the `FetchData.razor` page, **Grid with normal REST service** has been rendered. +## Performance Comparison: gRPC vs REST + +In this example, the **Index.razor** page renders a DataGrid using **gRPC service**, while the **FetchData.razor** page uses a **REST API**. The network performance for both approaches can be compared by analyzing **payload size** and **response time**. + +* **REST Service** + +* **Payload Size**: 616 B +* **Traffic Time**: 244 ms + +* **gRPC Service** + +* **Payload Size**: 14.4 KB +* **Traffic Time**: 15 ms + +The screenshot below illustrates the difference in payload and latency between gRPC and REST: -You can see both page **payload size** and **traffic time** in the following screenshot. In the screenshot above, you can see that the **REST service** has sent **616 B**, but the **gRPC service** has sent only **14.4 kB** Also **traffic time** for **REST** is **244ms** and the traffic time for **gRPC** is **15ms** only. +![Difference between gRPC service and REST service in Blazor](../images/difference-grpc.png) -![Difference between gRPC service and REST service in Blazor](../images/difference-grpc.png) \ No newline at end of file +N> **Observation**: gRPC demonstrates significantly lower latency compared to REST, making it suitable for high-performance scenarios in Blazor applications. \ No newline at end of file diff --git a/blazor/common/data-binding/restful-service-binding.md b/blazor/common/data-binding/restful-service-binding.md index d9c606d09d..68ad5e73d1 100644 --- a/blazor/common/data-binding/restful-service-binding.md +++ b/blazor/common/data-binding/restful-service-binding.md @@ -7,107 +7,114 @@ control: Common documentation: ug --- -# Bind data from RESTful web services to Syncfusion® Blazor components +# Bind data from RESTful web services to Syncfusion Blazor components -This article shows how to retrieve data from a RESTful web services, bind it to the Grid component, and perform CRUD operations. Data is fetched from an ODatav4 service using the [ODataV4Adaptor](https://blazor.syncfusion.com/documentation/data/adaptors#odatav4-adaptor) of `SfDataManager`. +## Introduction -Choose the suitable adaptor based on the RESTful service which you are using to bind data for the Syncfusion® Blazor component. Refer to the following documentation to know about the available Adaptors of SfDataManager. - * [Adaptors](https://blazor.syncfusion.com/documentation/data/adaptors) +This section provides an overview of how to bind data from RESTful services to Syncfusion® Blazor components. It explains the process of retrieving data from an OData service, integrating it with the Blazor DataGrid using [SfDataManager](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Data.SfDataManager.html) and [ODataV4Adaptor](https://blazor.syncfusion.com/documentation/data/adaptors#odatav4-adaptor), and enabling CRUD operations. The goal is to create a seamless data flow between the service and the UI components for building interactive and data-driven applications. + +Select an adaptor that matches the RESTful service implementation. For details on available adaptors, refer to the SfDataManager [Adaptors documentation](https://blazor.syncfusion.com/documentation/data/adaptors). ## Prerequisite software -The following software are required: -* Visual Studio 2022 -* .NET 6.0 or later +The following software and packages are required to implement data binding from RESTful services to Syncfusion® Blazor components: + +* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/) (latest version with .NET 10 support) +* [.NET 8 or later](https://dotnet.microsoft.com/en-us/download/dotnet) +* SQL Server (LocalDB or any supported edition) + +These components provide the development environment required for creating the database, building the OData service, and integrating the Blazor application. ## Create the database -Open Visual Studio , select **View -> SQL Server Object Explorer**. Right-click on the Databases folder to create a new Database and name it as OrdersDetails. +Create a database named OrdersDetails in SQL Server to store order information. + +1. Open **Visual Studio** and navigate to **View → SQL Server Object Explorer**. ![Add new database in Blazor](../images/odata-add-db.png) + +2. Right-click the **Databases** node and select **Add New Database**. Enter the name **OrdersDetails**. + ![Adding database name and location in Blazor](../images/odata-db-name.png) -Right-click on the **Tables** folder of the created database and click **Add New Table**. +3. Under the newly created database, right-click **Tables** and choose **Add New Table**. ![Add table in Blazor](../images/odata-add-table.png) -Use the following query to add a new table named **Orders**. +4. Use the following SQL script to define the **Orders** table: ``` -Create Table Orders( - OrderID BigInt Identity(1,1) Primary Key Not Null, - CustomerID Varchar(100) Not Null, - Freight int Null, - OrderDate datetime null -) +CREATE TABLE Orders ( + OrderID BIGINT IDENTITY(1,1) PRIMARY KEY NOT NULL, + CustomerID VARCHAR(100) NOT NULL, + Freight INT NULL, + OrderDate DATETIME NULL ``` -Now, the Orders table design will look like below. Click on the **Update** button. +After applying the script, the table design will appear as shown: ![Database table design in Blazor](../images/odata-table-design.png) -Now, click on **Update Database**. +Finally, click Update Database to apply changes. ![Update database in Blazor](../images/odata-update-db.png) -## Create OData service project +## OData Service Setup -Open Visual Studio 2022 and create an empty ASP.NET Core Web Application named ODataServiceProject. After creating the application, install the [Microsoft.AspNetCore.OData](https://www.nuget.org/packages/Microsoft.AspNetCore.OData/) package by running the following command in the Package Manager Console. +Create an OData service to expose the **OrdersDetails** database for consumption by the Blazor application. -``` -Install-Package Microsoft.AspNetCore.OData +### Create ASP.NET Core Web API project -``` -This package contains everything you need to create OData v4.0 endpoints using ASP.NET Core MVC and to support OData query syntax for your web APIs. +1. Open **Visual Studio 2022 or later** and create an **ASP.NET Core Web API** project named **ODataServiceProject**. -### Generate DbContext and model class from the database +2. Select **.NET 8 or newer** as the target framework. -Now, you need to scaffold **DbContext** and **model classes** from the existing **OrdersDetails** database. To perform scaffolding and work with the SQL Server database in our application, install the following NuGet packages. +### Install required nuGet packages -* [Microsoft.EntityFrameworkCore.Tools](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools) : This package creates database context and model classes from the database. +Install the following NuGet packages: -* [Microsoft.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/) :The database provider that allows [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/) to work with SQL Server. + - [Microsoft.EntityFrameworkCore.Tools](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools) – Provides scaffolding commands. + - [Microsoft.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/) – Enables SQL Server support. + - [Microsoft.AspNetCore.OData](https://www.nuget.org/packages/Microsoft.AspNetCore.OData/) -Run the following commands in the **Package Manager Console**. +**Options to install**: + +* Using **NuGet Package Manager** in Visual Studio: +Navigate to: **Tools → NuGet Package Manager → Manage NuGet Packages for Solution**. + +* Using **Package Manager Console**: + +{% tabs %} +{% highlight C# tabtitle="Package Manager" %} -``` Install-Package Microsoft.EntityFrameworkCore.Tools Install-Package Microsoft.EntityFrameworkCore.SqlServer +Install-Package Microsoft.AspNetCore.OData -``` +{% endhighlight %} +{% endtabs %} -Once the above packages are installed, you can scaffold DbContext and Model classes. Run the following command in the **Package Manager Console**. +### Scaffold DbContext and Model Classes -``` -Scaffold-DbContext “Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False” Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -``` +Run the following command to generate **DbContext** and entity classes from the **OrdersDetails** database: -The above scaffolding command contains the following details for creating DbContext and model classes for the existing database and its tables. -* **Connection string**: Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False -* **Data provider**: Microsoft.EntityFrameworkCore.SqlServer -* **Output directory**: -OutputDir Models +```powershell +Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models +``` -After running the above command, the **OrdersDetailsContext.cs** and **Orders.cs** files will be created under the **ODataServiceProject.Models** folder as follows. +This command creates **OrdersDetailsContext.cs** and **Orders.cs** under the **Models** folder. ![Models folder in Blazor](../images/odata-models.png) -You can see that OrdersDetailsContext.cs file contains the connection string details in the **OnConfiguring** method. - {% tabs %} {% highlight c# tabtitle="OrdersDetailsContext.cs" hl_lines="24" %} -using System; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata; namespace ODataServiceProject.Models { public partial class OrdersDetailsContext : DbContext { - public OrdersDetailsContext() - { - } - public OrdersDetailsContext(DbContextOptions options) : base(options) { @@ -115,227 +122,180 @@ namespace ODataServiceProject.Models public virtual DbSet Orders { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + protected override void OnModelCreating(ModelBuilder modelBuilder) { - if (!optionsBuilder.IsConfigured) + modelBuilder.Entity(entity => { - optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"); - } + entity.HasKey(e => e.OrderId); + entity.Property(e => e.CustomerId).HasMaxLength(100); + entity.Property(e => e.OrderDate).HasColumnType("datetime"); + }); } - - ... } } - {% endhighlight %} {% endtabs %} -It is not recommended to have a connection string with sensitive information in the OrdersDetailsContext.cs file, so the connection string is moved to the **appsettings.json** file. {% tabs %} -{% highlight json tabtitle="appsettings.json" %} +{% highlight c# tabtitle="Orders.cs" %} +using System; +namespace ODataServiceProject.Models { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + public partial class Orders + { + public long OrderId { get; set; } + public string CustomerId { get; set; } = string.Empty; + public int? Freight { get; set; } + public DateTime? OrderDate { get; set; } } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "OrdersDetailsDatabase": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" - } } - {% endhighlight %} {% endtabs %} -Now, the DbContext must be configured using connection string and registered as scoped service using the AddDbContext method in **Program.cs**. +### Configure Connection String + +Move the connection string to **appsettings.json**: + +```json +{ + "ConnectionStrings": { + "OrdersDetailsDatabase": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=OrdersDetails;Integrated Security=True" + } +} +``` + +Register the DbContext in **Program.cs**: {% tabs %} -{% highlight c# tabtitle=".NET 6 & .NET 7 (~/Program.cs)" %} +{% highlight c# tabtitle="~/Program.cs" %} -builder.Services.AddDbContext(option => - option.UseSqlServer(builder.Configuration.GetConnectionString("OrdersDetailsDatabase"))); +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("OrdersDetailsDatabase"))); {% endhighlight %} {% endtabs %} -### Creating ODataV4 service -The application is now configured to connect with the **OrdersDetails** database using [Entity Framework](https://learn.microsoft.com/en-us/ef/core/). Now, it’s time to consume data from the OrdersDetails database. To do so, you need an OData controller to serve data from the DbContext to the Blazor application. +### Add OData Controller -To create OData controller, right-click **Controller** folder in ODataServiceProject and select **Add -> New Item -> API controller with read/write actions**. We are naming this controller as **OrdersController** as it returns Orders table records. - -Now, replace the controller with the following code which contains code to handle CRUD operations in the Orders table. +Create an **OrdersController** in the **Controllers** folder and implement CRUD operations: {% tabs %} {% highlight c# tabtitle="OrdersController.cs" %} -using Microsoft.AspNet.OData; -using System.Threading.Tasks; -using ODataServiceProject.Models; +using Microsoft.AspNetCore.OData.Routing.Controllers; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.OData.Query; +using ODataServiceProject.Models; -// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 - -namespace ODataServiceProject.Controllers +[Route("odata/[controller]")] +public class OrdersController : ODataController { - [Route("api/[controller]")] - public class OrdersController : ODataController + private readonly OrdersDetailsContext _db; + + public OrdersController(OrdersDetailsContext context) { - private OrdersDetailsContext _db; - public OrdersController(OrdersDetailsContext context) - { - _db = context; - } - [HttpGet] - [EnableQuery] - public IActionResult Get() - { - return Ok(_db.Orders); - } - [EnableQuery] - public async Task Post([FromBody] Orders book) - { - _db.Orders.Add(book); - _db.SaveChanges(); - return Created(book); - } - [EnableQuery] - public async Task Patch([FromODataUri] long key, [FromBody] Delta book) - { - var entity = await _db.Orders.FindAsync(key); - book.Patch(entity); - await _db.SaveChangesAsync(); - return Updated(entity); - } - [EnableQuery] - public long Delete([FromODataUri] long key) - { - var deleterow = _db.Orders.Find(key); - _db.Orders.Remove(deleterow); - _db.SaveChanges(); - return key; - } + _db = context; } -} -{% endhighlight %} -{% endtabs %} - -Add the following line in the **launchSettings.json** file. + [EnableQuery] + [HttpGet] + public IActionResult Get() => Ok(_db.Orders); -{% tabs %} -{% highlight json tabtitle="launchSettings.json" %} + [EnableQuery] + [HttpPost] + public IActionResult Post([FromBody] Orders order) + { + _db.Orders.Add(order); + _db.SaveChanges(); + return Created(order); + } -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:59323", - "sslPort": 44392 + [EnableQuery] + [HttpPatch] + public IActionResult Patch([FromODataUri] long key, [FromBody] Delta order) + { + var entity = _db.Orders.Find(key); + order.Patch(entity); + _db.SaveChanges(); + return Updated(entity); } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "odata/orders", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "ODataServiceProject": { - "commandName": "Project", - "dotnetRunMessages": "true", - "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } + + [HttpDelete] + public IActionResult Delete([FromODataUri] long key) + { + var entity = _db.Orders.Find(key); + _db.Orders.Remove(entity); + _db.SaveChanges(); + return NoContent(); } - } } {% endhighlight %} {% endtabs %} -Additionally, make sure to include the AddCors() and UseCors() methods in **Program.cs** file of ODataService project when configuring with a Blazor Web App. -Open **Program.cs** file in .NET 6 and .NET 7 application and configure by referring to the following codes. - -{% tabs %} -{% highlight c# tabtitle=".NET 6 & .NET 7 (~/Program.cs)" %} +### Enable OData Routing -var builder = WebApplication.CreateBuilder(args); +Configure OData in **Program.cs**: -// Add services to the container. +{% tabs %} +{% highlight c# tabtitle="~/Program.cs" %} +builder.Services.AddControllers().AddOData(opt => + opt.AddRouteComponents("odata", GetEdmModel()) + .Count().Filter().OrderBy().Expand().Select().SetMaxTop(null)); static IEdmModel GetEdmModel() { - ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); - var books = builder.EntitySet("Orders"); - FunctionConfiguration myFirstFunction = books.EntityType.Collection.Function("MyFirstFunction"); - myFirstFunction.ReturnsCollectionFromEntitySet("Orders"); + var builder = new ODataConventionModelBuilder(); + builder.EntitySet("Orders"); return builder.GetEdmModel(); } -builder.Services.AddControllers(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(c => -{ - c.SwaggerDoc("v1", new() { Title = "ODataTutorial", Version = "v1" }); -}); -builder.Services.AddDbContext(option => - option.UseSqlServer(builder.Configuration.GetConnectionString("OrdersDetailsDatabase"))); -builder.Services.AddControllers().AddOData(opt => opt.AddRouteComponents("odata", GetEdmModel()).Count().Filter().OrderBy().Expand().Select().SetMaxTop(null)); -//if your configured with Blazor Web App only, call AddCors method +{% endhighlight %} +{% endtabs %} + +If the service is consumed by a **Blazor Web App**, enable **CORS**: + +{% tabs %} +{% highlight c# tabtitle="~/Program.cs" %} builder.Services.AddCors(options => { - options.AddPolicy("NewPolicy", builder => - builder.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader()); + options.AddPolicy("AllowBlazorApp", policy => + policy.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader()); }); -var app = builder.Build(); -//if your configured with Blazor Web App only, call UseCors method -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} -app.UseHttpsRedirection(); -app.UseCors("NewPolicy"); -app.UseAuthorization(); - -app.MapControllers(); - -app.Run(); +var app = builder.Build(); +app.UseCors("AllowBlazorApp"); {% endhighlight %} {% endtabs %} -## Create Blazor Web App +## Blazor App Setup + +### Create a Blazor Application Create a **Blazor Web App** using Visual Studio 2022 via [Microsoft templates](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling) or the [Syncfusion® Blazor Extension](https://blazor.syncfusion.com/documentation/visual-studio-integration/template-studio). Configure the appropriate [interactive render mode](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes#render-modes) and [interactivity location](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling#interactivity-location) when creating the Blazor Web App. -## Create Blazor Server Application +### Install Syncfusion® Blazor Packages + +Install the following NuGet packages: -Create a **Blazor Server App** using Visual Studio via [Microsoft templates](https://learn.microsoft.com/en-us/aspnet/core/blazor/tooling) or the [Syncfusion® Blazor Extension](https://blazor.syncfusion.com/documentation/visual-studio-integration/template-studio). +- [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) +- [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/) -## Add Syncfusion® Blazor Grid and Themes NuGet in Blazor App +**Options to install**: -To add **Blazor DataGrid** component in the app, open the NuGet package manager in Visual Studio (*Tools → NuGet Package Manager → Manage NuGet Packages for Solution*), search and install [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) and [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/). +* **Using NuGet Package Manager in Visual Studio** -If using `WebAssembly` or `Auto` render modes in a Blazor Web App, install Syncfusion® Blazor NuGet packages in the client project. + Navigate to: **Tools → NuGet Package Manager → Manage NuGet Packages for Solution**. -Alternatively, you can utilize the following package manager command to achieve the same. +* **Using Package Manager Console**: {% tabs %} {% highlight C# tabtitle="Package Manager" %} @@ -346,9 +306,11 @@ Install-Package Syncfusion.Blazor.Themes -Version {{ site.releaseversion }} {% endhighlight %} {% endtabs %} -N> Syncfusion® Blazor components are available in [nuget.org](https://www.nuget.org/packages?q=syncfusion.blazor). Refer to [NuGet packages](https://blazor.syncfusion.com/documentation/nuget-packages) topic for available NuGet packages list with component details. +N > Syncfusion® Blazor components are available on [nuget.org](https://www.nuget.org/packages?q=syncfusion.blazor). Refer to [NuGet packages](https://blazor.syncfusion.com/documentation/nuget-packages) for a complete list. -Open **~/_Imports.razor** file and import the following namespace. +### Configure Syncfusion® Services + +Import namespaces in **_Imports.razor**: {% highlight razor %} @@ -357,35 +319,20 @@ Open **~/_Imports.razor** file and import the following namespace. {% endhighlight %} -Now, register the Syncfusion® Blazor Service in the **~/Program.cs** file of your App. - -For a Blazor Web App with `WebAssembly` or `Auto (Server and WebAssembly)` interactive render mode, register the Syncfusion® Blazor service in both **~/Program.cs** files of your web app. +Register Syncfusion® services in **Program.cs**: ```cshtml - -.... using Syncfusion.Blazor; -.... -builder.Services.AddSyncfusionBlazor(); -.... +builder.Services.AddSyncfusionBlazor(); ``` -Themes provide life to components. Syncfusion® Blazor has different [themes](https://blazor.syncfusion.com/documentation/appearance/themes). They are: - -* Bootstrap5 -* Material 3 -* Tailwind CSS -* High Contrast -* Fluent +* For **Auto** render mode, register Syncfusion services in both **Program.cs** files (client and server projects). +* For **Blazor Server**, register in the server-side **Program.cs** only. -In this demo application, the latest theme is used. +### Add Theme Stylesheet - * For **Blazor Web App**, reference the stylesheet inside the `` of **~/Pages/_Layout.cshtml**. - * For **Blazor WebAssembly App**, reference the stylesheet inside the `` of **~/wwwroot/index.html**. - * For **Blazor Server App**, reference the stylesheet inside the `` of - * **~/Pages/_Host.cshtml** file for .NET 7. - * **~/Pages/_Layout.cshtml** file for .NET 6. +Include the Syncfusion theme in the section: {% highlight cshtml %} @@ -393,32 +340,46 @@ In this demo application, the latest theme is used. {% endhighlight %} -* For **Blazor Web App**, reference scripts in end of ``section at `~/Components/App.razor` file. -* For **Blazor WASM App**, reference scripts in end of ``section at `~/wwwroot/index.html` file. -* For **Blazor Server App**, reference scripts in end of ``section at `~/Pages/_Layout.cshtml` file for `.NET 6` project and in `~/Pages/_Host.cshtml` file for `.NET 7` project. +Add this stylesheet in the following locations based on the project type: + +* **Blazor Web App**: **~/Components/App.razor** +* **Blazor WebAssembly**: **wwwroot/index.html** +* **Blazor Server**: **~/Pages/_Host.cshtml** + + +### Add Script Reference + +Include the Syncfusion script at the end of the : ```html - .... + ``` -## Add Syncfusion® Blazor DataGrid component to an application +## Binding Data to Blazor DataGrid Using ODataV4Adaptor -In previous steps, you have successfully configured the Syncfusion® Blazor package in the application. Now, you can add the grid component to the `.razor` page inside the `Pages` folder. +To bind data from the OData service to the Syncfusion® Blazor DataGrid, use the [SfDataManager](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Data.SfDataManager.html) component with the [ODataV4Adaptor](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Adaptors.html#Syncfusion_Blazor_Adaptors_ODataV4Adaptor). This enables seamless integration with OData endpoints for operations such as **querying**, **sorting**, **paging**, and **CRUD**. -If you have set the interactivity location to `Per page/component` in the web app, ensure that you define a render mode at the top of the Syncfusion® Blazor component-included razor page as follows: +**Define Render Mode** + +If the interactivity location is set to **Per page/component**, specify the render mode at the top of the Razor page: {% tabs %} {% highlight razor %} -@* Your App render mode define here *@ @rendermode InteractiveAuto {% endhighlight %} {% endtabs %} +If the interactivity location is set to **Global**, the render mode is configured during project creation and does not need to be defined in individual Razor pages. + +**Add the DataGrid Component** + +Insert the Syncfusion [DataGrid](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html) in a Razor page inside the **Pages** folder: + {% tabs %} {% highlight razor %} @@ -427,11 +388,9 @@ If you have set the interactivity location to `Per page/component` in the web ap {% endhighlight %} {% endtabs %} -## Binding data to Blazor DataGrid component using ODataV4Adaptor +**Bind data Using SfDataManager and WebApiAdaptor** -To consume data from the OData controller, add **SfDataManager** with **ODataV4Adaptor**. Refer to the following documentation for more details on ODataV4Adaptor. - -[ODataV4Adaptor](https://blazor.syncfusion.com/documentation/data/adaptors#odatav4-adaptor) +Include `SfDataManager` within the grid and specify the OData service URL and adaptor type. {% tabs %} {% highlight razor %} @@ -443,9 +402,11 @@ To consume data from the OData controller, add **SfDataManager** with **ODataV4A {% endhighlight %} {% endtabs %} -N> In the example above, a localhost URL is used. Replace it with the actual URL of your OData service. +N> Replace the localhost URL with the actual OData service endpoint. + +**Define Grid Columns** -Grid columns can be defined by using the [GridColumn](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html) component. We are going to create columns using the following code. +Configure columns using the [GridColumn](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html) component: {% tabs %} {% highlight razor %} @@ -476,7 +437,7 @@ Grid columns can be defined by using the [GridColumn](https://help.syncfusion.co {% endhighlight %} {% endtabs %} -When you run the application, the **Get()** method will be called in your OData controller. +When the application runs, the **Get()** method in the OData controller will be invoked: {% tabs %} {% highlight c# %} @@ -501,12 +462,13 @@ public class OrdersController : ODataController {% endhighlight %} {% endtabs %} -## Handling CRUD operations with our Syncfusion® Blazor DataGrid component +## Handling CRUD Operations in Blazor DataGrid -Enable editing in the grid component using [GridEditSettings](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridEditSettings.html). The Grid supports several editing modes: [Inline/Normal](https://blazor.syncfusion.com/documentation/datagrid/in-line-editing), [Dialog](https://blazor.syncfusion.com/documentation/datagrid/dialog-editing), and [Batch](https://blazor.syncfusion.com/documentation/datagrid/batch-editing). +The Syncfusion® Blazor DataGrid supports full **CRUD** functionality when integrated with an OData service. Editing is enabled using the [GridEditSettings](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridEditSettings.html) component, and operations are performed through the OData controller methods. -Here, Inline edit mode is used with the Toolbar to show editing actions. -We have added the DataGrid Editing and Toolbar code with previous Grid model. +**Enable Editing** + +Configure editing in the grid using `GridEditSettings`. The grid supports multiple editing modes such as [Inline](https://blazor.syncfusion.com/documentation/datagrid/in-line-editing), [Dialog](https://blazor.syncfusion.com/documentation/datagrid/dialog-editing), and [Batch](https://blazor.syncfusion.com/documentation/datagrid/batch-editing). The example below uses Inline mode with the [Toolbar](https://blazor.syncfusion.com/documentation/datagrid/tool-bar) property to show toolbar items for editing. {% tabs %} {% highlight razor %} @@ -538,11 +500,11 @@ We have added the DataGrid Editing and Toolbar code with previous Grid model. {% endhighlight %} {% endtabs %} -N> Normal editing is the default mode. Set the [IsPrimaryKey](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html#Syncfusion_Blazor_Grids_GridColumn_IsPrimaryKey) property to **true** for the column that holds a unique key. +N> [IsPrimaryKey](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html#Syncfusion_Blazor_Grids_GridColumn_IsPrimaryKe) must be set to **true** for the column that holds a unique key. -### Insert a row +### Insert a record -To insert a new row, click the **Add** toolbar button. The new record edit form will look like below. +Click **Add** in the toolbar to create a new record. The grid sends a **POST** request to the OData controller: ![Insert Operation in Blazor](../images/odata-add-one.png) @@ -551,11 +513,12 @@ Clicking the **Update** toolbar button will insert the record in the Orders tabl {% tabs %} {% highlight c# tabtitle="OrdersController.cs" %} -public async Task Post([FromBody] Orders book) +[HttpPost] +public async Task Post([FromBody] Orders order) { - _db.Orders.Add(book); - _db.SaveChanges(); - return Created(book); + _db.Orders.Add(order); + await _db.SaveChangesAsync(); + return Created(order); } {% endhighlight %} @@ -563,22 +526,19 @@ public async Task Post([FromBody] Orders book) ![Insert Operation in Blazor](../images/odata-add-two.png) -### Update a row - -To edit a row, select any row and click the **Edit** toolbar button. The edit form will look like below. Edit the Customer Name column. +### Update a record -![Update Operation in Blazor](../images/odata-update-one.png) - -Clicking the **Update** toolbar button will update the record in the Orders table by calling the below **PATCH** method of the OData controller. +Click **Edit** in the toolbar to modify an existing record. The grid sends a **PATCH** request: {% tabs %} {% highlight c# tabtitle="OrdersController.cs" %} -public async Task Patch([FromODataUri] long key, [FromBody] Delta book) +[HttpPatch] +public IActionResult Patch([FromODataUri] long key, [FromBody] Delta order) { - var entity = await _db.Orders.FindAsync(key); - book.Patch(entity); - await _db.SaveChangesAsync(); + var entity = _db.Orders.Find(key); + order.Patch(entity); + _db.SaveChanges(); return Updated(entity); } @@ -589,19 +549,20 @@ The resultant grid will look like below. ![Update Operation in Blazor](../images/odata-update-two.png) -### Delete a row +### Delete a record -To delete a row, select any row and click the **Delete** toolbar button. Deleting operation will send a **DELETE** request to the OData controller with the selected record's primary key value to remove the corresponding record from the Orders table. +Click **Delete** in the toolbar to remove a record. The grid sends a **DELETE** request: {% tabs %} {% highlight c# tabtitle="OrdersController.cs" %} -public long Delete([FromODataUri] long key) +[HttpDelete] +public IActionResult Delete([FromODataUri] long key) { - var deleterow = _db.Orders.Find(key); - _db.Orders.Remove(deleterow); + var entity = _db.Orders.Find(key); + _db.Orders.Remove(entity); _db.SaveChanges(); - return key; + return NoContent(); } {% endhighlight %} From 17b7bf7c4d0013af23c71f4f9e929ff9d2bba5bd Mon Sep 17 00:00:00 2001 From: SadhanaBaskaran Date: Tue, 25 Nov 2025 12:39:53 +0530 Subject: [PATCH 2/2] 994264: Updated the UG content and samples for Blazor DataBinding Common folder section --- .../common/data-binding/grpc-data-binding.md | 485 +++++++++--------- 1 file changed, 242 insertions(+), 243 deletions(-) diff --git a/blazor/common/data-binding/grpc-data-binding.md b/blazor/common/data-binding/grpc-data-binding.md index 689df4ec21..b96656065b 100644 --- a/blazor/common/data-binding/grpc-data-binding.md +++ b/blazor/common/data-binding/grpc-data-binding.md @@ -7,7 +7,7 @@ component: Common documentation: ug --- -# Bind Data to the Syncfusion® Blazor Components Using gRPC Service +# Bind Data to the Syncfusion Blazor Components Using gRPC Service ## Introduction @@ -15,13 +15,13 @@ This section describes how to consume data from a [gRPC](https://grpc.io/) servi **What is gRPC?** -**gRPC** (gRPC Remote Procedure Call) is an open-source framework developed by Google for high-performance communication between distributed systems. It uses HTTP/2 for transport and Protocol Buffers for message serialization, making it faster and more efficient than JSON-based REST APIs. **gRPC** allows client applications to invoke server methods as if they were local, supports multiple programming languages, and provides features such as streaming and strong typing. +**gRPC** (gRPC Remote Procedure Call) is an open-source framework developed by Google for high-performance communication between distributed systems. It uses **HTTP/2** for transport and Protocol Buffers for message serialization, making it faster and more efficient than JSON-based REST APIs. **gRPC** allows client applications to invoke server methods as if they were local, supports multiple programming languages, and provides features such as streaming and strong typing. ## Prerequisite software The following software must be installed before configuring gRPC with Syncfusion® Blazor components: -* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/) (latest version with .NET 10 support) +* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/) * [.NET 8 or later](https://dotnet.microsoft.com/en-us/download/dotnet) ## Creating Blazor webassembly application @@ -43,41 +43,41 @@ Install the required NuGet packages in the **Shared**, **Server**, and **Client* * **Shared Project** -* [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf) – Provides Protocol Buffers serialization. -* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client/) – Enables gRPC client functionality. -* [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) – Generates strongly typed classes from .proto files. + * [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf) – Provides Protocol Buffers serialization. + * [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client/) – Enables gRPC client functionality. + * [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) – Generates strongly typed classes from .proto files. * **Server Project** -* [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCore/) – Adds gRPC server support. -* [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web/) – Enables gRPC-Web for browser-based clients. + * [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCore/) – Adds gRPC server support. + * [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web/) – Enables gRPC-Web for browser-based clients. * **Client Project** -* [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web/) – Provides gRPC-Web client support. + * [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web/) – Provides gRPC-Web client support. **Options to Install** -* Using NuGet Package Manager in Visual Studio +* Using **NuGet Package Manager** in Visual Studio * Navigate to: Tools → NuGet Package Manager → Manage NuGet Packages for Solution -Select the appropriate project and install the packages listed above. + Select the appropriate project and install the packages listed above. -* **Using Package Manager Console** +* Using **Package Manager Console** -{% tabs %} -{% highlight C# tabtitle="Package Manager" %} + {% tabs %} + {% highlight C# tabtitle="Package Manager" %} -Install-Package Google.Protobuf -ProjectName Shared -Install-Package Grpc.Net.Client -ProjectName Shared -Install-Package Grpc.Tools -ProjectName Shared -Install-Package Grpc.AspNetCore -ProjectName Server -Install-Package Grpc.AspNetCore.Web -ProjectName Server -Install-Package Grpc.Net.Client.Web -ProjectName Client + Install-Package Google.Protobuf -ProjectName Shared + Install-Package Grpc.Net.Client -ProjectName Shared + Install-Package Grpc.Tools -ProjectName Shared + Install-Package Grpc.AspNetCore -ProjectName Server + Install-Package Grpc.AspNetCore.Web -ProjectName Server + Install-Package Grpc.Net.Client.Web -ProjectName Client -{% endhighlight %} -{% endtabs %} + {% endhighlight %} + {% endtabs %} ## Add proto file and service @@ -85,113 +85,114 @@ Proto files are written in the Protocol Buffers language and define the structur 1. **Add the .proto File** -Create a Protocol Buffers file to define the **gRPC service** and message structure. -Steps: + Create a Protocol Buffers file to define the **gRPC service** and **message structure**. -1. In the **Shared** project, right-click and select **Add → New Item**. -2. Add a new file named **order.proto**. -3. Replace the default content with the following: + **Steps**: -{% tabs %} -{% highlight proto tabtitle="order.proto" %} -syntax = "proto3"; + 1. In the **Shared** project, right-click and select **Add → New Item**. + 2. Add a new file named **order.proto**. + 3. Replace the default content with the following: -import "google/protobuf/empty.proto"; -import "google/protobuf/timestamp.proto"; + {% tabs %} + {% highlight proto tabtitle="order.proto" %} + syntax = "proto3"; -option csharp_namespace = "BlazorAPPgRPC.Shared"; -package Orders; + import "google/protobuf/empty.proto"; + import "google/protobuf/timestamp.proto"; -service OrdersService { - rpc GetOrders (google.protobuf.Empty) returns (OrdersResponse); -} + option csharp_namespace = "BlazorAPPgRPC.Shared"; + package Orders; -message OrdersResponse { - repeated Orders orders = 1; -} + service OrdersService { + rpc GetOrders (google.protobuf.Empty) returns (OrdersResponse); + } -message Orders { - google.protobuf.Timestamp dateTimeStamp = 1; - int32 OrderID = 2; - string CustomerName = 3; - string ShipCountry = 4; - string ShipCity = 5; -} -{% endhighlight %} -{% endtabs %} + message OrdersResponse { + repeated Orders orders = 1; + } -**Configure Build Action**: + message Orders { + google.protobuf.Timestamp dateTimeStamp = 1; + int32 OrderID = 2; + string CustomerName = 3; + string ShipCountry = 4; + string ShipCity = 5; + } + {% endhighlight %} + {% endtabs %} + + **Configure Build Action**: -* Set **Build Action** to **Protobuf Compiler**. -* Select **Client** and **Server** for gRPC Stub Classes. + * Set **Build Action** to **Protobuf Compiler**. + * Select **Client** and **Server** for gRPC Stub Classes. -![Proto file properties in Blazor](../images/proto-file-properties.png) + ![Proto file properties in Blazor](../images/proto-file-properties.png) 2. **Add Partial Class for Orders** -Extend the generated **Orders** class in the **Shared** project with an additional property for easier date handling: + Extend the generated **Orders** class in the **Shared** project with an additional property for easier date handling: -{% tabs %} -{% highlight C# tabtitle="Orders.cs" %} -using Google.Protobuf.WellKnownTypes; -using System; + {% tabs %} + {% highlight C# tabtitle="Orders.cs" %} + using Google.Protobuf.WellKnownTypes; + using System; -namespace BlazorAPPgRPC.Shared -{ - public partial class Orders + namespace BlazorAPPgRPC.Shared { - public DateTime OrderDate + public partial class Orders { - get => DateTimeStamp.ToDateTime(); - set => DateTimeStamp = Timestamp.FromDateTime(value.ToUniversalTime()); + public DateTime OrderDate + { + get => DateTimeStamp.ToDateTime(); + set => DateTimeStamp = Timestamp.FromDateTime(value.ToUniversalTime()); + } } } -} -{% endhighlight %} -{% endtabs %} + {% endhighlight %} + {% endtabs %} 3. **Implement the gRPC Service** -Create a **Services** folder in the **Server** project and add **OrdersService.cs** to implement the gRPC service logic: - -{% tabs %} -{% highlight C# tabtitle="OrdersService.cs" %} -using BlazorAPPgRPC.Shared; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; + Create a **Services** folder in the **Server** project and add **OrdersService.cs** to implement the gRPC service logic: -public class OrdersService : OrdersServiceBase -{ - private static readonly string[] Countries = { "Berlin", "Tokyo", "Denmark", "Oslo" }; - private static readonly string[] Names = { "VINET", "RIO", "RAJ", "MAH", "RAM" }; - private static readonly string[] Cities = { "New York", "London", "Hue" }; + {% tabs %} + {% highlight C# tabtitle="OrdersService.cs" %} + using BlazorAPPgRPC.Shared; + using Google.Protobuf.WellKnownTypes; + using Grpc.Core; - public override Task GetOrders(Empty request, ServerCallContext context) + public class OrdersService : OrdersServiceBase { - var response = new OrdersResponse(); - response.Orders.AddRange(GetOrders()); - return Task.FromResult(response); - } + private static readonly string[] Countries = { "Berlin", "Tokyo", "Denmark", "Oslo" }; + private static readonly string[] Names = { "VINET", "RIO", "RAJ", "MAH", "RAM" }; + private static readonly string[] Cities = { "New York", "London", "Hue" }; - private IEnumerable GetOrders() - { - var rng = new Random(); - return Enumerable.Range(1, 365).Select(index => new Orders + public override Task GetOrders(Empty request, ServerCallContext context) { - OrderID = index, - OrderDate = DateTime.Now.AddDays(index), - ShipCountry = Countries[rng.Next(Countries.Length)], - CustomerName = Names[rng.Next(Names.Length)], - ShipCity = Cities[rng.Next(Cities.Length)] - }); + var response = new OrdersResponse(); + response.Orders.AddRange(GetOrders()); + return Task.FromResult(response); + } + + private IEnumerable GetOrders() + { + var rng = new Random(); + return Enumerable.Range(1, 365).Select(index => new Orders + { + OrderID = index, + OrderDate = DateTime.Now.AddDays(index), + ShipCountry = Countries[rng.Next(Countries.Length)], + CustomerName = Names[rng.Next(Names.Length)], + ShipCity = Cities[rng.Next(Cities.Length)] + }); + } } -} -{% endhighlight %} -{% endtabs %} + {% endhighlight %} + {% endtabs %} -N> The **OrdersService** class inherits from **OrdersServiceBase**, which is generated from the **.proto** file. + N> The **OrdersService** class inherits from **OrdersServiceBase**, which is generated from the **.proto** file. ## Configure gRPC and gRPC-Web @@ -201,165 +202,165 @@ To enable communication between the Blazor WebAssembly client and the server usi * **Register gRPC Services** -Add the gRPC service and required dependencies in the **ConfigureServices** method of **Startup.cs**: + Add the gRPC service and required dependencies in the **ConfigureServices** method of **Startup.cs**: -{% tabs %} -{% highlight C# tabtitle="Startup.cs" %} -public void ConfigureServices(IServiceCollection services) -{ - services.AddScoped(); - services.AddGrpc(); - // Other service registrations -} -{% endhighlight %} -{% endtabs %} + {% tabs %} + {% highlight C# tabtitle="Startup.cs" %} + public void ConfigureServices(IServiceCollection services) + { + services.AddScoped(); + services.AddGrpc(); + // Other service registrations + } + {% endhighlight %} + {% endtabs %} * **Enable gRPC-Web Middleware** -Add the gRPC-Web middleware in the **Configure** method. This must be placed **after UseRouting** and **before UseEndpoints**: + Add the gRPC-Web middleware in the **Configure** method. This must be placed **after UseRouting** and **before UseEndpoints**: -{% highlight csharp %} -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - app.UseRouting(); - app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); - app.UseEndpoints(endpoints => + {% highlight csharp %} + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - endpoints.MapGrpcService(); - // Other endpoints - }); -} -{% endhighlight %} + app.UseRouting(); + app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + // Other endpoints + }); + } + {% endhighlight %} 2. **Client Configuration** -In the Client project, create a gRPC-Web channel and register the gRPC client in **Program.cs**:` - -{% tabs %} -{% highlight C# tabtitle="Program.cs" %} -using Grpc.Net.Client; -using Grpc.Net.Client.Web; -using Microsoft.AspNetCore.Components; + In the **Client** project, create a gRPC-Web channel and register the gRPC client in **Program.cs**:` -public static async Task Main(string[] args) -{ - var builder = WebAssemblyHostBuilder.CreateDefault(args); + {% tabs %} + {% highlight C# tabtitle="Program.cs" %} + using Grpc.Net.Client; + using Grpc.Net.Client.Web; + using Microsoft.AspNetCore.Components; - builder.Services.AddSingleton(services => + public static async Task Main(string[] args) { - var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler())); - var backendUrl = services.GetRequiredService().BaseUri; - var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient }); - return new OrdersService.OrdersServiceClient(channel); - }); + var builder = WebAssemblyHostBuilder.CreateDefault(args); + + builder.Services.AddSingleton(services => + { + var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler())); + var backendUrl = services.GetRequiredService().BaseUri; + var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient }); + return new OrdersService.OrdersServiceClient(channel); + }); - await builder.Build().RunAsync(); -} -{% endhighlight %} -{% endtabs %} + await builder.Build().RunAsync(); + } + {% endhighlight %} + {% endtabs %} -N> The **OrdersService.OrdersServiceClient** class is generated automatically from the **.proto** file. + N> The **OrdersService.OrdersServiceClient** class is generated automatically from the **.proto** file. ## Add Syncfusion® Blazor DataGrid -The Syncfusion® Blazor DataGrid component will be used to display data retrieved from the gRPC service. +The Syncfusion® Blazor [DataGrid](https://blazor.syncfusion.com/documentation/datagrid/getting-started) component will be used to display data retrieved from the gRPC service. 1. **Install Syncfusion NuGet Package** -Install the required NuGet package in the Client project: + Install the required NuGet package in the Client project: -* [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) -* [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/) + * [Syncfusion.Blazor.Grid](https://www.nuget.org/packages/Syncfusion.Blazor.Grid/) + * [Syncfusion.Blazor.Themes](https://www.nuget.org/packages/Syncfusion.Blazor.Themes/) -**Options to install**: + **Options to install**: -* **Using NuGet Package Manager** + * **Using NuGet Package Manager** - Navigate to: **Tools → NuGet Package Manager → Manage NuGet Packages for Solution** + Navigate to: **Tools → NuGet Package Manager → Manage NuGet Packages for Solution** - Select the Client project and install above packages. + Select the Client project and install above packages. -* **Using Package Manager Console** + * **Using Package Manager Console** - {% tabs %} - {% highlight C# tabtitle="Package Manager Console" %} + {% tabs %} + {% highlight C# tabtitle="Package Manager Console" %} - Install-Package Syncfusion.Blazor.Grid -ProjectName Client + Install-Package Syncfusion.Blazor.Grid -ProjectName Client - {% endhighlight %} - {% endtabs %} + {% endhighlight %} + {% endtabs %} 2. **Register Syncfusion Services** -Add the required namespaces in **_Imports.razor**: + Add the required namespaces in **_Imports.razor**: -{% highlight razor %} + {% highlight razor %} -@using Syncfusion.Blazor -@using Syncfusion.Blazor.Grids + @using Syncfusion.Blazor + @using Syncfusion.Blazor.Grids -{% endhighlight %} + {% endhighlight %} -Register Syncfusion® services in **Program.cs**: + Register Syncfusion® services in **Program.cs**: -{% tabs %} -{% highlight C# tabtitle="Program.cs" %} -using Syncfusion.Blazor; + {% tabs %} + {% highlight C# tabtitle="Program.cs" %} + using Syncfusion.Blazor; -namespace BlazorAPPgRPC.Client -{ - public class Program + namespace BlazorAPPgRPC.Client { - public static async Task Main(string[] args) + public class Program { - var builder = WebAssemblyHostBuilder.CreateDefault(args); - builder.RootComponents.Add("#app"); - builder.Services.AddSyncfusionBlazor(); - await builder.Build().RunAsync(); + public static async Task Main(string[] args) + { + var builder = WebAssemblyHostBuilder.CreateDefault(args); + builder.RootComponents.Add("#app"); + builder.Services.AddSyncfusionBlazor(); + await builder.Build().RunAsync(); + } } } -} -{% endhighlight %} -{% endtabs %} + {% endhighlight %} + {% endtabs %} 3. **Apply Theme stylesheet** -Include the Syncfusion theme in **wwwroot/index.html**: + Include the Syncfusion theme in the **<head>** section of **wwwroot/index.html**: -{% highlight cshtml %} + {% highlight cshtml %} - + -{% endhighlight %} + {% endhighlight %} -Add this stylesheet in the following locations based on the project type: + Add this stylesheet in the following locations based on the project type: -* **Blazor Web App**: **~/Components/App.razor** -* **Blazor WebAssembly**: **wwwroot/index.html** -* **Blazor Server**: **~/Pages/_Host.cshtml** + * **Blazor Web App**: **~/Components/App.razor** + * **Blazor WebAssembly**: **wwwroot/index.html** + * **Blazor Server**: **~/Pages/_Host.cshtml** 4. **Add Script Reference** -Include the Syncfusion script at the end of the : + Include the Syncfusion script at the end of the **<body>**: -{% highlight cshtml %} + {% highlight cshtml %} - + -{% endhighlight %} + {% endhighlight %} 5. **Add DataGrid Component** -Insert the [DataGrid](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html) component in **Index.razor**: + Insert the [DataGrid](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html) component in **Index.razor**: -{% tabs %} -{% highlight razor %} - + {% tabs %} + {% highlight razor %} + - -{% endhighlight %} -{% endtabs %} + + {% endhighlight %} + {% endtabs %} ## Bind data to Blazor DataGrid component @@ -367,78 +368,76 @@ To display data from the gRPC service in the Syncfusion - - - - - - - - -} + Configure the `DataGrid` with [GridColumn](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridColumn.html) mapped to the Orders model: -@code { - private IList orders; + {% tabs %} + {% highlight razor %} +

Orders

+

This component demonstrates fetching data from the gRPC service.

- protected override async Task OnInitializedAsync() + @if (orders == null) + { +

Loading...

+ } + else { - orders = (await OrdersServiceClient.GetOrdersAsync(new Empty())).Orders; + + + + + + + + + } -} -{% endhighlight %} -{% endtabs %} -![Binding data from gRPC service in Blazor](../images/binding-data-from-grpc-service.png) + @code { + private IList orders; + + protected override async Task OnInitializedAsync() + { + orders = (await OrdersServiceClient.GetOrdersAsync(new Empty())).Orders; + } + } + {% endhighlight %} + {% endtabs %} + + ![Binding data from gRPC service in Blazor](../images/binding-data-from-grpc-service.png) 3. **Verify gRPC Communication** -After running the application, open the **Network tab** in browser developer tools. Reload the page and check the **GetOrders** request. The response headers should include **content-type: application/grpc-web**, confirming gRPC-Web is used. + After running the application, open the **Network tab** in browser developer tools. Reload the page and check the **GetOrders** request. The response headers should include **content-type: application/grpc-web**, confirming gRPC-Web is used. -![Checking gRPC in Blazor](../images/grpc-check.png) + ![Checking gRPC in Blazor](../images/grpc-check.png) ## Performance Comparison: gRPC vs REST -In this example, the **Index.razor** page renders a DataGrid using **gRPC service**, while the **FetchData.razor** page uses a **REST API**. The network performance for both approaches can be compared by analyzing **payload size** and **response time**. +The **Index.razor** page renders a `DataGrid` using a **gRPC service**, while the **FetchData.razor** page uses a **REST API**. Network performance for both approaches can be evaluated by analyzing **payload size** and **response time**. * **REST Service** -* **Payload Size**: 616 B -* **Traffic Time**: 244 ms + * **Payload Size**: 616 B + * **Traffic Time**: 244 ms * **gRPC Service** -* **Payload Size**: 14.4 KB -* **Traffic Time**: 15 ms - -The screenshot below illustrates the difference in payload and latency between gRPC and REST: + * **Payload Size**: 14.4 KB + * **Traffic Time**: 15 ms ![Difference between gRPC service and REST service in Blazor](../images/difference-grpc.png)