GRPC Service Create Using .NET Core 6.0 Entity Framework For CRUD Operation

I will try to make concise explanations for better understanding for the beginner level.

What Is REST?

We all Know REST (Representational State Transfer) is an architectural style that provides guidelines for designing web APIs.

It uses our existing standard HTTP 1.1 methods like GET, POST, PUT, and DELETE to work with server-side resources. REST APIs provide pre-defined URLs that the client must use to connect with the server.

GRPC means Google Remote Procedure Call

So building a GRPC application we have to create GRPC Service and later for consuming we have to create the client

GRPC service Create Using .NET core 6.0 EntityFramework for CRUD operation

In the project we need to install the below nuget package.

Grpc.AspNetCore is already installed by default when you create the project.

GRPC service Create Using .NET core 6.0 EntityFramework for CRUD operation

Create Database Blazor
USE [Blazor]
CREATE TABLE [dbo].[products]
  (
     [productrowid] [INT] IDENTITY(1, 1) NOT NULL,
     [productid]    [VARCHAR](20) NOT NULL,
     [productname]  [VARCHAR](200) NOT NULL,
     [categoryname] [VARCHAR](200) NOT NULL,
     [manufacturer] [VARCHAR](200) NOT NULL,
     [price]        [INT] NOT NULL,
     PRIMARY KEY CLUSTERED ( [productrowid] ASC )WITH (pad_index = OFF,
     statistics_norecompute = OFF, ignore_dup_key = OFF, allow_row_locks = on,
     allow_page_locks = on, optimize_for_sequential_key = OFF) ON [PRIMARY],
     UNIQUE NONCLUSTERED ( [productid] ASC )WITH (pad_index = OFF,
     statistics_norecompute = OFF, ignore_dup_key = OFF, allow_row_locks = on,
     allow_page_locks = on, optimize_for_sequential_key = OFF) ON [PRIMARY]
  )
ON [PRIMARY]
go 

Now run the below nuget command .using the Entity Framework Core Database First approach to generate entities in the project. Run the following command from the command prompt to scaffold entities from the database

dotnet tool install --global dotnet-ef --version 3.1.4
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Blazor;Integrated Security=SSPI" Microsoft.EntityFrameworkCore.SqlServer -o Models

Once this command runs successfully, the Models folder will be added in the project. This folder will contain the Product.cs and AppContext.cs files. Copy the connection string from the AppContext class and paste it in the appsettings.json as shown in listing.

"ConnectionStrings": {
    "AppDbContext": "Data Source=.;Initial Catalog=Blazor;Integrated Security=SSPI"
}

GRPC service Create Using .NET core 6.0 EntityFramework for CRUD operation

Create a new “products.proto” class

GRPC service Create Using .NET core 6.0 EntityFramework for CRUD operation

To access the gRPC service in client application like ASP.NET Core, Blazor, etc we need to install Grpc.AspNetCore.Web package in the gRPC project. This package provides gRPC-Web support for ASP.NET Core alongside gRPC HTTP/2 support.

package products;
service ProductsService {
    rpc GetAll(Empty) returns(Products);
    rpc GetById(ProductRowIdFilter) returns(Product);
    rpc Post(Product) returns(Product);
    rpc Put(Product) returns(Product);
    rpc Delete(ProductRowIdFilter) returns(Empty);
}
message Empty {}
message Product {
    int32 ProductRowId = 1;
    string ProductId = 2;
    string ProductName = 3;
    string CategoryName = 4;
    string Manufacturer = 5;
    int32 Price = 6;
}
message ProductRowIdFilter {
    int32 productRowId = 1;
}
message Products {
    repeated Product items = 1;
}

The Products Structure 

The products.proto file contains following message formats

  • Product, this is a message data structure for exchanging product data
  • ProductRowIdFilter, this is a message structure to read the product record based on ProductRowId (fetch by ID basically)
  • Products, this is a message structure that will be used to get the products collection
  • Empty, a message structure which represents the empty response from server and empty data to be sent from client to server.

To see the C# code from the proto file, modify the project file 

Right-Click on the products.proto file and check the below properties

Now, build the project, the C# files will be generated in the obj folder like below

Now in the Services folder add a new class file and name it as ProductsAppService.cs.

Here is the full code of the “ProductsAppService.cs” class

using Grpc.Core;
using GrpcService;
using GrpcService.Models;
using System.Linq;
using System.Threading.Tasks;
using static GrpcService.ProductsService;
namespace GrpcService.Services {
    public class ProductsAppService: ProductsServiceBase {
        public BlazorContext dbContext;
        public ProductsAppService(BlazorContext DBContext) {
            dbContext = DBContext;
        }
        #region GetAll
        public override Task < Products > GetAll(Empty request, ServerCallContext context) {
            Products response = new Products();
            var products = from prd in dbContext.Products
            select new Product() {
                ProductRowId = prd.ProductRowId,
                    ProductId = prd.ProductId,
                    ProductName = prd.ProductName,
                    CategoryName = prd.CategoryName,
                    Manufacturer = prd.Manufacturer,
                    Price = prd.Price
            };
            response.Items.AddRange(products.ToArray());
            return Task.FromResult(response);
        }
        #endregion
        #region GetById
        public override Task < Product > GetById(ProductRowIdFilter request, ServerCallContext context) {
            var product = dbContext.Products.Find(request.ProductRowId);
            var searchedProduct = new Product() {
                ProductRowId = product.ProductRowId,
                    ProductId = product.ProductId,
                    ProductName = product.ProductName,
                    CategoryName = product.CategoryName,
                    Manufacturer = product.Manufacturer,
                    Price = product.Price
            };
            return Task.FromResult(searchedProduct);
        }
        #endregion
        #region PostInsert
        public override Task < Product > Post(Product request, ServerCallContext context) {
            var prdAdded = new Models.Product() {
                ProductId = request.ProductId,
                    ProductName = request.ProductName,
                    CategoryName = request.CategoryName,
                    Manufacturer = request.Manufacturer,
                    Price = request.Price
            };
            var res = dbContext.Products.Add(prdAdded);
            dbContext.SaveChanges();
            var response = new Product() {
                ProductRowId = res.Entity.ProductRowId,
                    ProductId = res.Entity.ProductId,
                    ProductName = res.Entity.ProductName,
                    CategoryName = res.Entity.CategoryName,
                    Manufacturer = res.Entity.Manufacturer,
                    Price = res.Entity.Price
            };
            return Task.FromResult < Product > (response);
        }
        #endregion
        #region PUTUPDATE
        public override Task < Product > Put(Product request, ServerCallContext context) {
            Models.Product prd = dbContext.Products.Find(request.ProductRowId);
            if (prd == null) {
                return Task.FromResult < Product > (null);
            }
            prd.ProductRowId = request.ProductRowId;
            prd.ProductId = request.ProductId;
            prd.ProductName = request.ProductName;
            prd.CategoryName = request.CategoryName;
            prd.Manufacturer = request.Manufacturer;
            prd.Price = request.Price;
            dbContext.Products.Update(prd);
            dbContext.SaveChanges();
            return Task.FromResult < Product > (new Product() {
                ProductRowId = prd.ProductRowId,
                    ProductId = prd.ProductId,
                    ProductName = prd.ProductName,
                    CategoryName = prd.CategoryName,
                    Manufacturer = prd.Manufacturer,
                    Price = prd.Price
            });
        }
        #endregion
        #region DELETE
        public override Task < Empty > Delete(ProductRowIdFilter request, ServerCallContext context) {
            Models.Product prd = dbContext.Products.Find(request.ProductRowId);
            if (prd == null) {
                return Task.FromResult < Empty > (null);
            }
            dbContext.Products.Remove(prd);
            dbContext.SaveChanges();
            return Task.FromResult < Empty > (new Empty());
        }
        #endregion
    }
}

Now is the final step. Paste the below code at Program.cs file to register the AppDbContext and CORS policies in services as shown below

using GrpcService.Models;
using GrpcService.Services;
using Microsoft.EntityFrameworkCore;
using System;
var builder = WebApplication.CreateBuilder(args);
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddDbContext < BlazorContext > (item => item.UseSqlServer(builder.Configuration.GetConnectionString("AppDbContext")));
builder.Services.AddCors(options => {
    options.AddPolicy("cors", policy => {
        policy.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
    });
});
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService < GreeterService > ();
app.MapGrpcService < ProductsAppService > ();
app.MapGet("/", () => "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");
app.Run();

Now Build the project and make sure that there are no errors.

If there are no errors then the gRPC services will be hosted successfully as shown in below figure

GRPC service Create Using .NET core 6.0 EntityFramework for CRUD operation

So we have successfully created the GRPC service.

In my next article, we will show how to consume the gRPC Service in .NET Core Console Client Application

Note that these packages are applicable for any type of gRPC Client.Install-Package Grpc.Tools

  • Install-Package Grpc.Net.Client
  • Install-Package Google.Protobuf