Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Sep 23, 2022

CRUD Operation and Microservice Communication using gRPC in .NET Core 6 Web API

Author:
Jaydeep Patil
Source:
Views:
6122

In this article, we will discuss gRPC and perform CRUD Operation using that and step-by-step implementation of gRPC.

We take Product Application here to understand how things are going to work with gRPC and, in that first, we create ProductOfferGrpcService which is used to create Product Offers and which will be consumed by Admin Service and he will add, update and delete product offer and managed all the things related to that using gRPC Service. Secondly, we create another section in ProductOfferGrpcService for the User to get a list of offers which is added by the admin.

Agenda

  • Introduction of gRPC
  • Implementation of ProductOfferGrpcService and Admin.API Microservice
  • Implementation of User Console Application

Prerequisites

  • Visual Studio 2022
  • .NET Core 6 SDK
  • SQL Server

Introduction of gRPC

  • gRPC stands for Google Remote Procedure Calls.
  • gRPC is a modern open-source high-performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking, and authentication. It is also applicable in the last mile of distributed computing to connect devices, mobile applications, and browsers to backend services. — gRPC Page.


     
  • gRPC is the framework that is used to implement APIs using HTTP/2.
  • Basically, gRPC uses the protobuf for serialization and HTTP2 protocol which provides lots more advantages than HTTP.
  • gRPC clients and servers intercommunicate utilizing a variety of environments and machines, It Also supports many languages like Java, C#, Go, Ruby and Python.
  • The Binary layer of gRPC will do all data operations like encoding and it also uses protobuf as an intermediator between client and server, improving performance.
  • It is also used for communication between multiple microservices efficiently.

If you want some more details about gRPC and how it will work then I suggest you read my following article

gRPC Introduction And Implementation Using .NET Core 6

Implementation of ProductOfferGrpcService Service

Step 1

Create a new Blank Solution.

Step 2

Configure Project.

Step 3

Add a new gRPC Service Project inside the Blank Solution.

 

Step 4

Configure your new project.

 

Step 5

Provide additional information.

Remove default protobuf and service file from the project.

Project Structure

Step 6

Create Offer Class inside the Entities.

namespace ProductOfferGrpcService.Entities
{
    public class Offer
    {
        public int Id { get; set; }
        public string ProductName { get; set; }
        public string OfferDescription { get; set; }
    }
}

Step 7

Next, Create a new DbContextClass inside the Data folder.

using Microsoft.EntityFrameworkCore;
using ProductOfferGrpcService.Entities;

namespace ProductOfferGrpcService.Data
{
    public class DbContextClass : DbContext
    {
        protected readonly IConfiguration Configuration;

        public DbContextClass(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        }

        public DbSet<Offer> Offer { get; set; }
    }
}

Step 8

Later on, create IProductOfferService and ProductOfferService inside the Repositories folder.

IProductOfferService

using ProductOfferGrpcService.Entities;

namespace ProductOfferGrpcService.Repositories
{
    public interface IProductOfferService
    {
        public Task<List<Offer>> GetOfferListAsync();
        public Task<Offer> GetOfferByIdAsync(int Id);
        public Task<Offer> AddOfferAsync(Offer offer);
        public Task<Offer> UpdateOfferAsync(Offer offer);
        public Task<bool> DeleteOfferAsync(int Id);
    }
}

ProductOfferService

using Microsoft.EntityFrameworkCore;
using ProductOfferGrpcService.Data;
using ProductOfferGrpcService.Entities;

namespace ProductOfferGrpcService.Repositories
{
    public class ProductOfferService : IProductOfferService
    {
        private readonly DbContextClass _dbContext;

        public ProductOfferService(DbContextClass dbContext)
        {
            _dbContext = dbContext;
        }

        public async Task<List<Offer>> GetOfferListAsync()
        {
            return await _dbContext.Offer.ToListAsync();
        }

        public async Task<Offer> GetOfferByIdAsync(int Id)
        {
            return await _dbContext.Offer.Where(x => x.Id == Id).FirstOrDefaultAsync();
        }

        public async Task<Offer> AddOfferAsync(Offer offer)
        {
            var result = _dbContext.Offer.Add(offer);
            await _dbContext.SaveChangesAsync();
            return result.Entity;
        }

        public async Task<Offer> UpdateOfferAsync(Offer offer)
        {
            var result = _dbContext.Offer.Update(offer);
            await _dbContext.SaveChangesAsync();
            return result.Entity;
        }

        public async Task<bool> DeleteOfferAsync(int Id)
        {
            var filteredData = _dbContext.Offer.Where(x => x.Id == Id).FirstOrDefault();
            var result = _dbContext.Remove(filteredData);
            await _dbContext.SaveChangesAsync();
            return result != null ? true : false;
        }
    }
}

Step 9

Create OfferMapper inside AutoMapper folder.

using AutoMapper;
using ProductOfferGrpcService.Entities;
using ProductOfferGrpcService.Protos;

namespace ProductOfferGrpcService.AutoMapper
{
    public class OfferMapper : Profile
    {
        public OfferMapper()
        {
            CreateMap<Offer, OfferDetail>().ReverseMap();
        }
    }
}

Step 10

Next, create a new offer proto file inside Proto.

syntax = "proto3";
option csharp_namespace = "ProductOfferGrpcService.Protos";
service ProductOfferService {
    rpc GetOfferList (Empty) returns (Offers);
    rpc GetOffer (GetOfferDetailRequest) returns (OfferDetail);
    rpc CreateOffer (CreateOfferDetailRequest) returns (OfferDetail);
    rpc UpdateOffer (UpdateOfferDetailRequest) returns (OfferDetail);
    rpc DeleteOffer (DeleteOfferDetailRequest) returns (DeleteOfferDetailResponse);
}
message GetOfferDetailRequest {
    int32 productId = 1;
}
message OfferDetail {
    int32 id = 1;
    string productName = 2;
    string offerDescription = 3;
}
message CreateOfferDetailRequest {
    OfferDetail offer = 1;
}
message UpdateOfferDetailRequest {
    OfferDetail offer = 1;
}
message DeleteOfferDetailRequest {
    int32 productId = 1;
}
message DeleteOfferDetailResponse {
    bool isDelete = 1;
}
message Empty{
}
message Offers {
    repeated OfferDetail items = 1;
}

Also, make sure proto file properties are correct as I showed below and if that will be correct then build your project.
 

Step 11

Add a new Offer Service inside Services.

using AutoMapper;
using Grpc.Core;
using ProductOfferGrpcService.Entities;
using ProductOfferGrpcService.Protos;
using ProductOfferGrpcService.Repositories;
using ProductOfferService = ProductOfferGrpcService.Protos.ProductOfferService;

namespace ProductOfferGrpcService.Services
{
    public class OfferService : ProductOfferService.ProductOfferServiceBase
    {
        private readonly IProductOfferService _prductOfferService;
        private readonly IMapper _mapper;

        public OfferService(IProductOfferService prductOfferService, IMapper mapper)
        {
            _prductOfferService = prductOfferService;
            _mapper = mapper;
        }

        public async override Task<Offers> GetOfferList(Empty request, ServerCallContext context)
        {
            var offersData = await _prductOfferService.GetOfferListAsync();
            Offers response = new Offers();
            foreach (Offer offer in offersData)
            {
                response.Items.Add(_mapper.Map<OfferDetail>(offer));
            }

            return response;
        }

        public async override Task<OfferDetail> GetOffer(GetOfferDetailRequest request, ServerCallContext context)
        {
            var offer =  await _prductOfferService.GetOfferByIdAsync(request.ProductId);
            var offerDetail = _mapper.Map<OfferDetail>(offer);

            return offerDetail;
        }

        public async override Task<OfferDetail> CreateOffer(CreateOfferDetailRequest request, ServerCallContext context)
        {
            var offer = _mapper.Map<Offer>(request.Offer);
            await _prductOfferService.AddOfferAsync(offer);
            var offerDetail = _mapper.Map<OfferDetail>(offer);

            return offerDetail;
        }

        public async override Task<OfferDetail> UpdateOffer(UpdateOfferDetailRequest request, ServerCallContext context)
        {
            var offer = _mapper.Map<Offer>(request.Offer);
             await _prductOfferService.UpdateOfferAsync(offer);
            var offerDetail = _mapper.Map<OfferDetail>(offer);

            return offerDetail;
        }

        public async override Task<DeleteOfferDetailResponse> DeleteOffer(DeleteOfferDetailRequest request, ServerCallContext context)
        {
            var isDeleted =  await _prductOfferService.DeleteOfferAsync(request.ProductId);
            var response = new DeleteOfferDetailResponse
            {
                IsDelete = isDeleted
            };

            return response;
        }
    }
}

Step 12

Configure the database connection string inside the app settings file.

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=DESKTOP;;Initial Catalog=ProductOfferAsync;User Id=sa;Password=database;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  }
}

Step 13

Register and configure a few services inside the Program class.

using ProductOfferGrpcService.Data;
using ProductOfferGrpcService.Repositories;
using ProductOfferGrpcService.Services;

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.AddScoped<IProductOfferService, ProductOfferService>();
builder.Services.AddDbContext<DbContextClass>();
builder.Services.AddAutoMapper(typeof(Program).Assembly);
var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService<OfferService>();
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();

Implementation of Admin.API Microservice

Step 1

Create a new Admin.API Web API Project.

Project Structure

Step 2

Connect the ProductOfferGrpcService.

Right-Click on Admin.API and click on Connected Service in Add section.

Step 3

Add a new gRPC Service.

Step 4

Click on gRPC.

Step 5

Provide the protobuf file path and make sure your type of class is also correct.

Step 6

Click on finish it will configure all things.

Step 7

Create the Offer Class inside Entities.

namespace Admin.API.Entities
{
    public class Offer
    {
        public int Id { get; set; }
        public string ProductName { get; set; }
        public string OfferDescription { get; set; }
    }
}

Step 8

Next, add ProductOfferController.

using Admin.API.Entities;
using Grpc.Net.Client;
using Microsoft.AspNetCore.Mvc;
using ProductOfferGrpcService.Protos;

namespace Admin.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductOfferController : ControllerBase
    {
        private readonly GrpcChannel _channel;
        private readonly ProductOfferService.ProductOfferServiceClient _client;
        private readonly IConfiguration _configuration;

        public ProductOfferController(IConfiguration configuration)
        {
            _configuration = configuration;
            _channel = GrpcChannel.ForAddress(_configuration.GetValue<string>("GrpcSettings:OfferServiceUrl"));
            _client = new ProductOfferService.ProductOfferServiceClient(_channel);
        }

        [HttpGet("getofferlist")]
        public async Task<Offers> GetOfferListAsync()
        {
            try
            {
                var response =  await _client.GetOfferListAsync(new Empty { });

                return response;
            }
            catch
            {
            }

            return null;
        }

        [HttpGet("getofferbyid")]
        public async Task<OfferDetail> GetOfferByIdAsync(int Id)
        {
            try
            {
                var request = new GetOfferDetailRequest
                {
                     ProductId = Id
                };

                var response = await _client.GetOfferAsync(request);

                return response;
            }
            catch
            {
            }

            return null;
        }

        [HttpPost("addoffer")]
        public async Task<OfferDetail> AddOfferAsync(Offer offer)
        {
            try
            {
                var offerDetail = new OfferDetail
                {
                    Id = offer.Id,
                    ProductName = offer.ProductName,
                    OfferDescription = offer.OfferDescription
                };

                var response  = await _client.CreateOfferAsync(new CreateOfferDetailRequest()
                {
                    Offer = offerDetail
                });

                return response;
            }
            catch
            {
            }

            return null;
        }

        [HttpPut("updateoffer")]
        public async Task<OfferDetail> UpdateOfferAsync(Offer offer)
        {
            try
            {
                var offerDetail = new OfferDetail
                {
                    Id = offer.Id,
                    ProductName = offer.ProductName,
                    OfferDescription = offer.OfferDescription
                };

                var response = await _client.UpdateOfferAsync(new UpdateOfferDetailRequest()
                {
                    Offer = offerDetail
                });

                return response;
            }
            catch
            {
            }

            return null;
        }

        [HttpDelete("deleteoffer")]
        public async Task<DeleteOfferDetailResponse> DeleteOfferAsync(int Id)
        {
            try
            {
                var response = await _client.DeleteOfferAsync(new DeleteOfferDetailRequest()
                {
                    ProductId = Id
                });

                return response;
            }
            catch
            {
            }

            return null;
        }
    }
}

Step 9

Configure the gRPC Service URL inside the app settings file.

{
  "GrpcSettings": {
    "OfferServiceUrl": "http://localhost:5263"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Step 10

Right-Click on the solution and set both projects as a startup project.

Step 11

Finally, run your project.

Here you can use endpoints to manage offers through gRPC Service.

Implementation of User Console Application

We are going to create a console application to get a list of offers that which admin adds through gRPC.

Step 1

First, we create a new proto file inside ProductOfferGrpcService named as user offer proto file.

syntax = "proto3";
option csharp_namespace = "ProductOfferGrpcService.Protos";
service UserOfferService {
    rpc GetUserOfferList (EmptyRequestArg) returns (UserOffers);
}
message UserOfferDetail {
    int32 id = 1;
    string productName = 2;
    string offerDescription = 3;
}
message EmptyRequestArg{
}
message UserOffers {
    repeated UserOfferDetail items = 1;
}

Step 2

Create UserOfferMapper inside AutoMapper of ProductOfferGrpcService.

using AutoMapper;
using ProductOfferGrpcService.Entities;
using ProductOfferGrpcService.Protos;

namespace ProductOfferGrpcService.AutoMapper
{
    public class UserOfferMapper : Profile
    {
        public UserOfferMapper()
        {
            CreateMap<Offer, UserOfferDetail>().ReverseMap();
        }
    }
}

Step 3

Next, add a new UserOfferService inside the Services of ProductOfferGrpcService.

using AutoMapper;
using Grpc.Core;
using ProductOfferGrpcService.Protos;
using ProductOfferGrpcService.Repositories;
using ProductOfferService = ProductOfferGrpcService.Protos.UserOfferService;

namespace ProductOfferGrpcService.Services
{
    public class UsersOfferService : ProductOfferService.UserOfferServiceBase
    {
        private readonly IProductOfferService _prductOfferService;
        private readonly IMapper _mapper;

        public UsersOfferService(IProductOfferService prductOfferService, IMapper mapper)
        {
            _prductOfferService = prductOfferService;
            _mapper = mapper;
        }

        public async override Task<UserOffers> GetUserOfferList(EmptyRequestArg request, ServerCallContext context)
        {
            var offersData = await _prductOfferService.GetOfferListAsync();
            UserOffers response = new UserOffers();
            foreach (var offer in offersData)
            {
                response.Items.Add(_mapper.Map<UserOfferDetail>(offer));
            }

            return response;
        }
    }
}

Step 4

Configure UserOfferService inside the Program class of ProductOfferGrpcService.

using ProductOfferGrpcService.Data;
using ProductOfferGrpcService.Repositories;
using ProductOfferGrpcService.Services;

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.AddScoped<IProductOfferService, ProductOfferService>();
builder.Services.AddDbContext<DbContextClass>();
builder.Services.AddAutoMapper(typeof(Program).Assembly);

var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService<OfferService>();
app.MapGrpcService<UsersOfferService>();
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();

Step 5

Create a new User console application.

Step 6

Configure your project.

Step 7

Add a user offer proto file inside the User Application.

Step 8

Add a new reference service.

Step 9

Click on gRPC.

Step 10

Select file URL and type of class properly.

Step 11

Add code inside Program class which connects gRPC Service and takes a list of offers which is added by Admin.

using Grpc.Net.Client;
using ProductOfferGrpcService.Protos;

var channel = GrpcChannel.ForAddress("http://localhost:5263");
var client = new UserOfferService.UserOfferServiceClient(channel);
var serverReply = client.GetUserOfferList(new EmptyRequestArg { });

Console.WriteLine(serverReply);
Console.ReadLine();

Step 12

Finally, whenever you run your console application will see the latest offer added by the admin.

Output

Conclusion

Here we discussed gRPC and the step-by-step implementation of gRPC Product Service. Also, implementation of Admin service and User Application.

Happy learning!

Similar
Apr 24, 2022
Author: Dr Vin
Let’s find out which one is better .Net 6 or .Net 5 and how .Net has changed the game of software development. In the past, I have briefly talked about the Dot Net 6 framework that was released last year...
Sep 14, 2023
Author: Rico Fritzsche
Balancing Business Needs: Evaluating Architecture in Domain-Driven Design One topic has come up again and again over the years, sometimes more, sometimes less, in conversations among developers: What’s the best way to modularize software? As a longtime software developer, I’ve...
Aug 24, 2022
Author: Jaydeep Patil
In this article, we will learn about global exception handling implementation using .NET Core 6 Web API step-by-step. Agenda Introduction Implementation of Global Exception Handling Prerequisites Visual Studio 2022 .NET Core 6 SDK Understanding of C# Programming Basic Understanding of...
Nov 9, 2020
Author: Akhil Mittal
Microservices The term microservices portrays a software development style that has grown from contemporary trends to set up practices that are meant to increase the speed and efficiency of developing and managing software solutions at scale. Microservices is more about...
Send message
Type
Email
Your name
*Message