gRPC With Blazor, C# And .Net Core

Agenda 

  1. Introduction
  2. Project setup
  3. Implementing gRPC Service 
  4. Implementing Blazor App
  5. Integrating the Blazor and gRPC Service
  6. Source Code 

Introduction

 
gRPC has become the main talking point recently after the launch of the .Net core 3.0. This article will demonstrate one ToDo Blazor app which will be integrated to the gRPC service and perform the basic CRUD operation. If you are new to the gRPC and its terminologies just go through my previous articles.

Project setup

 
To get the gRPC Service as well as Blazor server up and running we need basic installation of two things
  • .Net Core SDK 3.0 or Later
  • Visual studio 2019
Now there are two types of projects we are going to add here first is the gRPC Project and another will be the gRPC service project.
 
Adding gRPC Service
 
Go to Add New Project and select gRPC Template which is Present as shown below image
 
 
Adding Blazor App
 
Here Open Add New Project wizard and select the Blazor App which will be the server-side Blazor App like in the image below.
 
 
 

Implementing gRPC Service

 
We have seen how we have set up the gRPC service project and then the client-side blazor app now in this section let's implement the service and the basic CRUD operation with it. As we all know gRPC uses ProtoBuff ( Protocol Buffers ) as an Interface Definition language for defining services and structure of the payload message.
 
In our case, we are going to implement the ToDo app which will perform all basic ToDo CRUD operations. The first step in implementing the gRPC service is to implement the protobuff file lets see step by step how we can manipulate the ProtoBuff file
 
Add New ProtoBuff File
 
To add new Proto file Right-click on the ToDoGrpc Service Project it will open add new Item wizard lets search for protocol buffer option
 
Let's name it ToDo.Proto
 
 
Before compiling this we need to make sure are we open the .csProj file of your project and make the following changes once so that our proto file will be compiled and it will generate the stub accordingly
  1. <ItemGroup>  
  2.   
  3. <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />  
  4.   
  5. <Protobuf Include="Protos\ToDo.proto" GrpcServices="Server" />  
  6.   
  7. <Protobuf Include="Protos\Sample.proto" GrpcServices="Server" />  
  8.   
  9. </ItemGroup>  
With these two changes, we are set for developing our services in the following steps
 
Defining Protocol Format
 
When we have added ToDo.Proto file we will have the following structure like below  
  1. syntax = "proto3";  
  2. option csharp_namespace = "ToDoGrpcService";  
  3. import "google/protobuf/empty.proto";  
  4.   
  5. package ToDo;  
  6.   
  7. service ToDoService{  
  8. rpc GetToDo(google.protobuf.Empty) returns (ToDoItems);  
  9. rpc GetToDoItem(ToDoQuery) returns (ToDoData );  
  10. rpc PostToDoItem(ToDoData) returns(ToDoPostResponse);  
  11. rpc PutToDoItem(ToDoPutQuery) returns(ToDoPostResponse);  
  12. rpc DeleteItem(ToDoQuery) returns (ToDoPostResponse);  
  13. }  
  14.   
  15. message ToDoData{  
  16. int32 Id=4;  
  17.     string Title=1;  
  18.     string Description=2;  
  19.     bool Status=3;  
  20. }  
  21.   
  22. message ToDoQuery{  
  23.     int32 id=1;  
  24. }  
  25.   
  26. message ToDoItems{  
  27.     repeated ToDoData ToDoItemList =1;  
  28. }  
  29.   
  30. message ToDoPutQuery{  
  31. ToDoData ToDoDataItem=1;  
  32. int32 Id=2;  
  33. }  
  34.   
  35. message ToDoPostResponse{  
  36.     string StatusMessage=1;  
  37.     bool Status=2;  
  38.     int32 StatusCode=3;  
  39. }  
Code Explanation
 
Package Declaration
  1. syntax = "proto3";    
  2. option csharp_namespace = "ToDoGrpcService";    
  3. import "google/protobuf/empty.proto";    
  4. package ToDo;    
Here we have to do some initial setup and import some packages. In the first line we are specifying the proto3 as a syntax for the proto file. Next is the CSharp namespace which will be the default namespace for the stub which will be generated. Next is the import section where we will be importing the empty.proto  file which we are going to use in the next section.
 
Defining the Message Payload
  1. message ToDoData{    
  2. int32 Id=4;    
  3.     string Title=1;    
  4.     string Description=2;    
  5.     bool Status=3;    
  6. }    
  7.     
  8. message ToDoQuery{    
  9.     int32 id=1;    
  10. }    
  11.     
  12. message ToDoItems{    
  13.     repeated ToDoData ToDoItemList =1;    
  14. }    
  15.     
  16. message ToDoPutQuery{    
  17. ToDoData ToDoDataItem=1;    
  18. int32 Id=2;    
  19. }    
  20.     
  21. message ToDoPostResponse{    
  22.     string StatusMessage=1;    
  23.     bool Status=2;    
  24.     int32 StatusCode=3;    
  25. }    
Code Explanation
 
Message Name
Fields
Description
ToDoData
Id,
Title
Description,
Status
This is the basic format for the ToDo list where Id , Title Description and status will be held.
ToDoQuery
id
This data structure will be used while querying the ToDo Item
ToDoItems
Repeated ToDoData
This will be a list of the ToDo Data Items
ToDoPutQuery
ToDoData ToDoDataItem
Id
This will be used in updating the ToDo Record where Id will hold the Id of the ToDo Item
ToDoPostResponse
StatusMessage,
Status,
StatusCode
This will be the Data which will be returned after All POST Operations.
 
Service Declaration
  1. service ToDoService{  
  2.    rpc GetToDo(google.protobuf.Empty) returns (ToDoItems);  
  3.    rpc GetToDoItem(ToDoQuery) returns (ToDoData );  
  4.    rpc PostToDoItem(ToDoData) returns(ToDoPostResponse);  
  5.    rpc PutToDoItem(ToDoPutQuery) returns(ToDoPostResponse);  
  6.    rpc DeleteItem(ToDoQuery) returns (ToDoPostResponse);  
  7. }  
Message Payload will define the data structure which will be passed to and from the service here we have the service definitions.
 
Service Name
Params
Returns
Description
GetToDo
Google.Protobuff.Empty
ToDoItems
It gets all the To Do Items from the database
GetToDoItem
ToDoQuery
ToDoData
It will give the Item based on the Id which is passed in the Query
PostToDoItem
ToDoData
ToDoPostResponse
This service will create new ToDo Item in Db
PutToDoItem
ToDoPutQery
ToDoPostResponse
It will update the Existing ToDo Item
DeleteItem
ToDoQuery
ToDoPostResponse
Deletes the ToDoItem
 
So far we have defined the services and messages. Now when these proto files are compiled successfully it will generate some stub which will be the base for the service implementation.
 
Service Implementations
 
Below is the code which will implement the actual service
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Google.Protobuf.WellKnownTypes;  
  6. using Grpc.Core;  
  7.   
  8. namespace ToDoGrpcService.Services  
  9. {  
  10.     public class ToDoDataService : ToDoService.ToDoServiceBase  
  11.     {  
  12.         private readonly ToDoDataContext _dataContext;  
  13.         public ToDoDataService(ToDoDataContext dataContext)  
  14.         {  
  15.               
  16.             _dataContext = dataContext;  
  17.              
  18.         }  
  19.   
  20.         /// <summary>  
  21.         /// Get All Data  
  22.         /// </summary>  
  23.         /// <param name="request"></param>  
  24.         /// <param name="context"></param>  
  25.         /// <returns></returns>  
  26.         public override Task<ToDoItems> GetToDo(Empty request, ServerCallContext context)  
  27.         {  
  28.             ToDoItems objItems = new ToDoItems();  
  29.   
  30.             foreach (var item in _dataContext.ToDoDbItems)  
  31.             {  
  32.                 objItems.ToDoItemList.Add(item);  
  33.             }  
  34.   
  35.             return Task.FromResult(objItems);  
  36.         }  
  37.   
  38.         /// <summary>  
  39.         /// Post Data   
  40.         /// </summary>  
  41.         /// <param name="request"></param>  
  42.         /// <param name="context"></param>  
  43.         /// <returns></returns>  
  44.         public override Task<ToDoPostResponse> PostToDoItem(ToDoData request, ServerCallContext context)  
  45.         {  
  46.              _dataContext.ToDoDbItems.Add(request);  
  47.             var result = _dataContext.SaveChanges();  
  48.             if (result>0)  
  49.             {  
  50.                 return Task.FromResult(new ToDoPostResponse()  
  51.                 {  
  52.                     Status = true,  
  53.                     StatusCode = 100,  
  54.                     StatusMessage = "Added Successfully"  
  55.                 });  
  56.             }  
  57.             else  
  58.             {  
  59.                 return Task.FromResult(new ToDoPostResponse()  
  60.                 {  
  61.                     Status = false,  
  62.                     StatusCode = 500,  
  63.                     StatusMessage = "Issue Occured."  
  64.                 });  
  65.             }  
  66.               
  67.         }  
  68.         /// <summary>  
  69.         /// Get Item with the Id  
  70.         /// </summary>  
  71.         /// <param name="request"></param>  
  72.         /// <param name="context"></param>  
  73.         /// <returns></returns>  
  74.   
  75.         public override Task<ToDoData> GetToDoItem(ToDoQuery request, ServerCallContext context)  
  76.         {  
  77.             var result = from data in _dataContext.ToDoDbItems  
  78.                          where data.Id == request.Id  
  79.                          select data;  
  80.             return Task.FromResult(result.First());  
  81.               
  82.         }  
  83.         /// <summary>  
  84.         /// Deletes the Item  
  85.         /// </summary>  
  86.         /// <param name="request"></param>  
  87.         /// <param name="context"></param>  
  88.         /// <returns></returns>  
  89.         public override Task<ToDoPostResponse> DeleteItem(ToDoQuery request, ServerCallContext context)  
  90.         {  
  91.   
  92.             var item = (from data in _dataContext.ToDoDbItems  
  93.                                     where data.Id == request.Id  
  94.                                     select data).Single();  
  95.   
  96.   
  97.               _dataContext.ToDoDbItems.Remove(item);  
  98.   
  99.             var result = _dataContext.SaveChanges();  
  100.   
  101.             if (result > 0)  
  102.             {  
  103.                 return Task.FromResult(new ToDoPostResponse()  
  104.                 {  
  105.                     Status = true,  
  106.                     StatusCode = 100,  
  107.                     StatusMessage = "Deleted Successfully"  
  108.                 });  
  109.             }  
  110.             else  
  111.             {  
  112.                 return Task.FromResult(new ToDoPostResponse()  
  113.                 {  
  114.                     Status = false,  
  115.                     StatusCode = 500,  
  116.                     StatusMessage = "Issue Occured."  
  117.                 });  
  118.             }  
  119.         }  
  120.         /// <summary>  
  121.         /// Updates the item  
  122.         /// </summary>  
  123.         /// <param name="request"></param>  
  124.         /// <param name="context"></param>  
  125.         /// <returns></returns>  
  126.         public override Task<ToDoPostResponse> PutToDoItem(ToDoPutQuery request, ServerCallContext context)  
  127.         {  
  128.             _dataContext.ToDoDbItems.Update(request.ToDoDataItem);  
  129.             var result = _dataContext.SaveChanges();  
  130.   
  131.   
  132.             if (result > 0)  
  133.             {  
  134.                 return Task.FromResult(new ToDoPostResponse()  
  135.                 {  
  136.                     Status = true,  
  137.                     StatusCode = 100,  
  138.                     StatusMessage = "Updated  Successfully "  
  139.                 });  
  140.             }  
  141.             else  
  142.             {  
  143.                 return Task.FromResult(new ToDoPostResponse()  
  144.                 {  
  145.                     Status = false,  
  146.                     StatusCode = 500,  
  147.                     StatusMessage = "Issue Occured."  
  148.                 });  
  149.             }  
  150.         }  
  151.     }  
  152. }  
Code Explanation
 
Here we are adding a class ToDoDataService.cs which is getting inherited from the ToDoService.ToDoServiceBase class which is nothing but the stub generated from our proto file which will have the definition of the services which we have defined in the Proto file. Next we have implemented all the methods in the Proto file which will perform the basic operations which we perform normally.
 
Startup Changes
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.AspNetCore.Builder;  
  6. using Microsoft.AspNetCore.Hosting;  
  7. using Microsoft.AspNetCore.Http;  
  8. using Microsoft.EntityFrameworkCore;  
  9. using Microsoft.Extensions.DependencyInjection;  
  10. using Microsoft.Extensions.Hosting;  
  11. using ToDoGrpcService.Services;  
  12.   
  13. namespace ToDoGrpcService  
  14. {  
  15.     public class Startup  
  16.     {  
  17.         // This method gets called by the runtime. Use this method to add services to the container.  
  18.         // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
  19.         public void ConfigureServices(IServiceCollection services)  
  20.         {  
  21.             services.AddGrpc();  
  22.             services.AddDbContext<ToDoDataContext>(options =>options.UseInMemoryDatabase("ToDoDatabase"));  
  23.               
  24.         }  
  25.   
  26.         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  27.         public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ToDoDataContext ctx)  
  28.         {  
  29.             if (env.IsDevelopment())  
  30.             {  
  31.                 app.UseDeveloperExceptionPage();  
  32.             }  
  33.   
  34.             new ToDoGenerator(ctx).ToDoDataSeed();  
  35.   
  36.             app.UseRouting();  
  37.               
  38.             app.UseEndpoints(endpoints =>  
  39.             {  
  40.                 endpoints.MapGrpcService<GreeterService>();  
  41.                 endpoints.MapGrpcService<ToDoDataService>();  
  42.   
  43.                 endpoints.MapGet("/", async context =>  
  44.                 {  
  45.                     await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");  
  46.                 });  
  47.             });  
  48.         }  
  49.     }  
  50. }  
Here a couple of changes are needed to get our service up and running. Map the endpoints to the gRPC service. In the first method, ConfigureServices, we are adding the gRPC Services in the collection and for our demo purpose we are using InMemoryDatabase so we are configuring the DbContext to use the InMemory Database
 
The next set of Changes is needed at the Configure Method where we will do Some Database seeding which will add the initial items in the database. The next change is at the map endpoints to the gRPC service. Here we are mapping the gRPC service implementation ToDoDataService to the endpoints.
 
Now we have implemented the Service. Let's try to implement the Client app which will be our Blazor server-side app. In the first project section we have added one Blazor project now let’s see the basic components which will operate for us. Follow the below step to get our app working
 
Initial setup and Nuget packages
 
Once we are done with adding a project we need to add some NuGet packages which will help in implementing the clients for the gRPC Nuget Package which will be needed will be like below,
  1. Google.ProtoBuff
  2. Grpc.Net.Client
  3. Grpc.Tools
Once we are done with the packages let's configure our client to compile and include the proto files
 

Adding Proto File and Configure gRPC Client

 
gRPC Clients are nothing but concrete types which are generated from the Proto files to generate the gRPC Client. Let's add our proto files in the Project; for that let us make a folder Called Proto.
 
Once they are added in the Project let's change and configure the Proto files to be compiled as a Client. In the service section we have made them be compiled as a service so let's modify our .csproj file and make them a client like below.
  1. <ItemGroup>  
  2.     <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />  
  3.     <Protobuf Include="Protos\ToDo.proto" GrpcServices="Client" />  
  4.   </ItemGroup>  
In this Section we have modified and made sure we are compiling our proto files as a client. How we can implement the client? Let's see while developing the services.
 
Add New Razor Component
 
Right-click on project -> Add New Item ->> Add New Razor Component. Name it ToDoOperation.razor like the image below.
 
 
Code for the Razor Component will be like below
  1. @page "/Todo"  
  2.   
  3. @inherits BlazorClient.CodeFiles.ToDoOperation  
  4.   
  5.   
  6. @if (toDoItems == null && toDoItems.ToDoItemList == null)  
  7. {  
  8.     <p><em>Loading...</em></p>  
  9. }  
  10.   
  11. <div style="background-color:#3a0647;color:white;font-family:Calibri;font-size:x-large;font-weight:500;text-align:center;border-radius:10px">  
  12.     To Do List  
  13. </div>  
  14. <hr style="color:#5c116f" />  
  15. <div class="row" style="padding-left:900px;padding-bottom:4px">  
  16.     <button id="btnAdd" @onclick="ShowAddpopup" style="background-color:#5c116f;color:white;font-family:Calibri">Add New ToDo</button>  
  17. </div>  
  18.   
  19.   
  20.   
  21.   
  22. @if (toDoItems != null && toDoItems.ToDoItemList != null)  
  23. {  
  24.     <div class="row" style=" text-align:center; background-color:#5c116f;color:white;font-family:Calibri;font-size:larger;  
  25.  border-radius:7px; font-weight:500">  
  26.         <div class="col-sm-2">Sr. No.</div>  
  27.         <div class="col-sm-2">Title</div>  
  28.         <div class="col-sm-2">Description</div>  
  29.         <div class="col-sm-2">Status</div>  
  30.     </div>  
  31.     @for (int i = 0; i < toDoItems?.ToDoItemList?.Count; i++)  
  32.     {  
  33.         var a = @toDoItems.ToDoItemList[i].Id;  
  34.   
  35.         <div class="row" style="text-align:center;font-family:Calibri;font-size:medium;font-weight:500;padding:1px">  
  36.             <div class="col-sm-2">@(i+1)</div>  
  37.             <div class="col-sm-2">@toDoItems.ToDoItemList[i].Title</div>  
  38.             <div class="col-sm-2">@toDoItems.ToDoItemList[i].Description</div>  
  39.             <div class="col-sm-2">@toDoItems.ToDoItemList[i].Status</div>  
  40.             <div class="col-sm-2" style="text-align:left">  
  41.                 <button class="btn btn-primary" @onclick="@(async () => await ShowEditForm(a))">Edit</button>  
  42.             </div>  
  43.             <div class="col-sm-2" style="text-align:left"> <button class="btn btn-danger" @onclick="@(async () =>  ShowDeletePopup(a.ToString()))">Remove</button> </div>  
  44.         </div>  
  45.     }  
  46. }  
  47. else  
  48. {  
  49.     <div class="row" style="text-align:center;font-family:Calibri;font-size:medium;font-weight:500;padding:1px">  
  50.         <h4> No To Do Item Found !! </h4>  
  51.         </div>  
  52.  }  
  53.   
  54.   
  55.   
  56.         @if (ShowModel == true)  
  57.         {  
  58.   
  59.             <div class="modal" tabindex="-1" style="display:block;" role="dialog">  
  60.                 <div class="modal-dialog">  
  61.                     <div class="modal-content">  
  62.                         <div class="modal-header" style="background-color:#5c116f;color:white;height:50px">  
  63.                             <span class="modal-title">@PopupTitle</span>  
  64.                             <button type="button" class="close" @onclick="DismissPopup">  
  65.                                 <span aria-hidden="true" style="color:white;">X</span>  
  66.                             </button>  
  67.                         </div>  
  68.                         <div class="modal-body">  
  69.   
  70.                             <table border="0" cellspacing="1">  
  71.                                 <tr>  
  72.                                     <td><strong>Title</strong></td>  
  73.                                     <td><input type="text" @bind="ToDoDataItem.Title" maxlength="20" /></td>  
  74.                                 </tr>  
  75.                                 <tr>  
  76.                                     <td><strong>Description</strong></td>  
  77.                                     <td><input type="text" @bind="ToDoDataItem.Description" maxlength="20" /></td>  
  78.                                 </tr>  
  79.                                 <tr>  
  80.                                     <td><strong>Status</strong></td>  
  81.                                     <td><input type="checkbox" @bind="ToDoDataItem.Status" /></td>  
  82.                                 </tr>  
  83.                                 <tr>  
  84.                                     <td colspan="2" align="center"><button class="btn btn-primary" id="btnPostData" @onclick="PostData">@ActionText</button></td>  
  85.   
  86.                                 </tr>  
  87.                             </table>  
  88.                         </div>  
  89.                     </div>  
  90.                 </div>  
  91.             </div>  
  92.         }  
  93.   
  94.   
  95.         @if (ShowAlert == true)  
  96.         {  
  97.   
  98.             <div class="modal" tabindex="-2" style="display:block;padding-top:-200px;padding-right:0px" role="dialog">  
  99.                 <div class="modal-dialog">  
  100.                     <div class="modal-content">  
  101.                         <div class="modal-header" style="background-color:#5c116f;color:white;height:50px">  
  102.                             <span class="modal-title">Notification</span>  
  103.                             <button type="button" class="close" @onclick="DismissPopup">  
  104.                                 <span aria-hidden="true" style="color:white;">X</span>  
  105.                             </button>  
  106.                         </div>  
  107.                         <div class="modal-body">  
  108.                             @OperationStatusText  
  109.                         </div>  
  110.                     </div>  
  111.                 </div>  
  112.             </div>  
  113.         }  
  114.   
  115.         @if (ShowModeletePopup == true)  
  116.         {  
  117.   
  118.             <div class="modal" tabindex="-3" style="display:block;padding-top:300px" role="dialog">  
  119.                 <div class="modal-dialog">  
  120.                     <div class="modal-content">  
  121.                         <div class="modal-header" style="background-color:#5c116f;color:white;height:50px">  
  122.                             <span class="modal-title">Status</span>  
  123.                             <button type="button" class="close" @onclick="DismissPopup">  
  124.                                 <span aria-hidden="true" style="color:white;">X</span>  
  125.                             </button>  
  126.                         </div>  
  127.                         <div class="modal-body">  
  128.                             <table>  
  129.                                 <tr>  
  130.                                     <td colspan="2">  
  131.                                         Are you sure you want to delete this ToDo Item with Id @DeleteItemId ?  
  132.                                     </td>  
  133.                                 </tr>  
  134.                                 <tr>  
  135.                                     <td align="right"><button class="btn btn-primary" @onclick="DeleteData">Ok</button></td>  
  136.                                     <td align="left"><button class="btn btn-danger">Cancel</button></td>  
  137.                                 </tr>  
  138.   
  139.                             </table>  
  140.                         </div>  
  141.                     </div>  
  142.                 </div>  
  143.             </div>  
  144.         }  
Add Component Class
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Grpc.Net.Client;  
  6. using Microsoft.AspNetCore.Components;  
  7.   
  8. namespace BlazorClient.CodeFiles  
  9. {  
  10.     public partial class ToDoOperation : ComponentBase  
  11.     {  
  12.         public bool ShowModel = false;  
  13.         public bool ShowAlert = false;  
  14.         public bool ShowModeletePopup = false;  
  15.         public string OperationStatusText = "";  
  16.         public string PopupTitle = "";  
  17.   
  18.         public BlazorClient.Data.ToDoDataItem ToDoDataItem = null;  
  19.         public string ActionText = "";  
  20.   
  21.         public ToDoGrpcService.ToDoItems toDoItems;  
  22.   
  23.         public string DeleteItemId { getset; }  
  24.   
  25.         [Inject]  
  26.         protected BlazorClient.Services.ToDoDataService ToDoService { getset; }   
  27.   
  28.   
  29.         protected override void OnInitialized()  
  30.         {  
  31.   
  32.             GetToDoList();  
  33.         }  
  34.   
  35.         protected void GetToDoList()  
  36.         {  
  37.   
  38.             toDoItems= ToDoService.GetToDoList();  
  39.         }  
  40.   
  41.         protected async Task ShowEditForm(int Id)  
  42.         {  
  43.               
  44.             PopupTitle = "To Do Edit";  
  45.             ActionText = "Update";  
  46.   
  47.             ToDoDataItem = ToDoService.GetToDoItem(Id);  
  48.             ShowModel = true;  
  49.         }  
  50.   
  51.         protected void ShowAddpopup()  
  52.         {  
  53.             ToDoDataItem = new Data.ToDoDataItem() { Title = "", Description = "", Status = false, Id = 0 };  
  54.             PopupTitle = "To Do Add";  
  55.             ActionText = "Add";  
  56.             ShowModel = true;  
  57.         }  
  58.         protected void ShowDeletePopup(string Id)  
  59.         {  
  60.             DeleteItemId = Id;  
  61.             ShowModeletePopup = true;  
  62.         }  
  63.   
  64.   
  65.   
  66.         protected void PostData()  
  67.         {  
  68.             bool status = false;  
  69.             if (ToDoDataItem.Id > 0)  
  70.             {  
  71.                 status = ToDoService.UpdateToDoData(this.ToDoDataItem);  
  72.   
  73.             }  
  74.             else  
  75.             {  
  76.                 status = ToDoService.AddToDoData(this.ToDoDataItem);  
  77.             }  
  78.             Reload(status);  
  79.         }  
  80.   
  81.         public void DeleteData()  
  82.         {  
  83.               
  84.             var operationStatus = ToDoService.DeleteData(DeleteItemId);  
  85.             Reload(operationStatus);  
  86.         }  
  87.   
  88.         protected void Reload(bool status)  
  89.         {  
  90.             ShowModeletePopup = false;  
  91.             ShowModel = false;  
  92.             GetToDoList();  
  93.             ShowAlert = true;  
  94.             if (status)  
  95.             {  
  96.                 OperationStatusText = "Processed Successfully !! ";  
  97.             }  
  98.             else  
  99.             {  
  100.                 OperationStatusText = "Error Occured  ";  
  101.             }  
  102.   
  103.         }  
  104.   
  105.         protected void DismissPopup()  
  106.         {  
  107.             ShowModel = false;  
  108.             ShowAlert = false;  
  109.             ShowModeletePopup = false;  
  110.         }  
  111.   
  112.     }  
  113. }  
Here in our code-behind code, we have injected a service ToDoDataService which will hold all our gRPC operations.
 
Design Service to Call gRPC Methods
 
Code for the ToDoData Service will be like below.
  1. using Grpc.Net.Client;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace BlazorClient.Services  
  8. {  
  9.     public class ToDoDataService  
  10.     {  
  11.   
  12.   
  13.         private ToDoGrpcService.ToDoService.ToDoServiceClient GetServiceClient()  
  14.         {  
  15.             var channel = GrpcChannel.ForAddress("https://localhost:5001");  
  16.             return new ToDoGrpcService.ToDoService.ToDoServiceClient(channel);  
  17.         }  
  18.   
  19.         public bool AddToDoData(Data.ToDoDataItem toDoDataItem)  
  20.         {  
  21.   
  22.             var client = GetServiceClient();  
  23.   
  24.             var todoData = new ToDoGrpcService.ToDoData()  
  25.             {  
  26.                 Status = toDoDataItem.Status,  
  27.                 Title = toDoDataItem.Title,  
  28.                 Description = toDoDataItem.Description  
  29.             };  
  30.   
  31.             var response = client.PostToDoItem(todoData, null);  
  32.             return response.Status;  
  33.   
  34.         }  
  35.         public bool UpdateToDoData(Data.ToDoDataItem toDoDataItem)  
  36.         {  
  37.             var client = GetServiceClient();  
  38.             var updateData = new ToDoGrpcService.ToDoPutQuery();  
  39.             updateData.Id = toDoDataItem.Id;  
  40.             updateData.ToDoDataItem = new ToDoGrpcService.ToDoData()  
  41.             {  
  42.                 Id = toDoDataItem.Id,  
  43.                 Status = toDoDataItem.Status,  
  44.                 Title = toDoDataItem.Title,  
  45.                 Description = toDoDataItem.Description  
  46.             };  
  47.             var response = client.PutToDoItem(updateData, null);  
  48.             return response.Status;  
  49.         }  
  50.         public bool DeleteData(string ToDoId)  
  51.         {  
  52.             var client = GetServiceClient();  
  53.             var response = client.DeleteItem(new ToDoGrpcService.ToDoQuery() { Id = Convert.ToInt32(ToDoId) }, null);  
  54.             return response.Status;  
  55.         }  
  56.         public ToDoGrpcService.ToDoItems GetToDoList()  
  57.         {  
  58.             var client = GetServiceClient();  
  59.             return  client.GetToDo(new Google.Protobuf.WellKnownTypes.Empty(), null);  
  60.               
  61.         }  
  62.   
  63.         public Data.ToDoDataItem GetToDoItem(int id)  
  64.         {  
  65.             var client = GetServiceClient();  
  66.             var todoItem = client.GetToDoItem(new ToDoGrpcService.ToDoQuery() { Id = Convert.ToInt32(id) }, null);  
  67.   
  68.             return new Data.ToDoDataItem() { Title = todoItem.Title, Description = todoItem.Description, Status = todoItem.Status, Id = todoItem.Id };  
  69.   
  70.         }  
  71.     }  
  72. }  
Here as you can see we have added all our methods like Add, Update, Delete Get Methods which will call their operations accordingly. Here we are creating the gRPC Client and that will be used to call all the operations.
 
Add Service in the Service Collection
 
To make sure service is available in the application let's add the service in the collection with a single line like below.
  1. services.AddSingleton<BlazorClient.Services.ToDoData
Once we have all this implemented we will have an output like below,
 
 
Source code
 
You can find all this source code here Source code