gRPC ASP.NET Core

【gRPC】使用ASP.NET Core 實作 gRPC

Mark Lu 2020/12/30 14:41:42
228

什麼是gRPC?

 

gRPC是有效連接服務和構建分佈式系統的框架。它最初由Google設計,現在是一個開源項目,旨在推廣用於服務之間通信遠端程序呼叫(RPC)模型。它專注於高性能,並使用HTTP / 2協議來傳輸二進制消息。它還依靠協議緩衝區語言來定義服務合同。協議緩衝區(Protocol Buffer),也稱為Protobuf,使您可以定義服務中使用的接口,以獨立於編程語言來為通信提供服務。提供了許多用於最常用編程語言的工具,可以將這些Protobuf接口轉換為代碼。

 

gRPC有四種不同類型的RPC

 

 

  • Unary RPC : 客戶端發送一個請求並獲取一個響應。
  • Server streaming RPC : 從客戶端獲取請求後,伺服器將響應流發送回去。
  • Client streaming RPC :客戶端發送一系列消息,等待服務器對其進行處理並收到單個響應。
  • Bidirectional streaming RPC : 客戶端和服務器在兩個方向上交換訊息。

 

使用ASP.NET Core 建立一個gRPC服務

 

 

 

 

Visual Studio會建立一個範例

 


 

Proto 檔案包含:

    GRPC 服務的定義。

 

    用戶端與伺服器之間傳送的訊息。

 

proto 檔的撰寫風格可以遵循官方的 Style Guide,才不會寫出來的 proto 檔跟其他開發者的習慣差太多

 

syntax = "proto3";

option csharp_namespace = "GrpcService";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

 

GrpcService實作proto定義

 

using Grpc.Core;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace GrpcService
{
    public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }

        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }
}

 

 建立一個 GrpcClient 的主控台應用程式

 

從 NuGet 安裝這三個 Packages:

Install-Package Google.Protobuf -Version 3.14.0
Install-Package Grpc.Net.Client -Version 2.34.0
Install-Package Grpc.Tools -Version 2.34.0

 

建立一個 protos 資料夾,將GrpcService專案中protos 資料夾的greet.proto,複製到GrpcClient的protos 資料夾,點擊greet.proto右鍵選擇屬性,將gRPC Stub Classes的Server only改成Client only

 

 

開啟greet.proto檔案,修改csharp_namespace 為 GrpcClient

 

syntax = "proto3";

option csharp_namespace = "GrpcClient";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

 

修改Program檔

 

using Grpc.Net.Client;
using System;
using System.Threading.Tasks;

namespace GrpcClient
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await Task.Delay(3000);

            using var channel = GrpcChannel.ForAddress("https://localhost:5001");

            var client = new Greeter.GreeterClient(channel);

            Console.WriteLine("請輸入你的名字...");

            String name = Console.ReadLine();

            var reply = client.SayHello(new HelloRequest { Name = name });

            Console.WriteLine("問候語 : " + reply.Message);

            await channel.ShutdownAsync();

            Console.WriteLine("按任何一個鍵退出...");
            Console.ReadKey();
        }
    }
}

 

點擊方案右鍵選擇屬性,將啟用專案修改成多個啟動專案,將GrpcService與GrpcClient設定為啟動。

 

 

執行

 

GrpcService

 

GrpcClient

 

輸入名字,按下enter,就可以收到 GrpcService的回應

 

 

 建立一個 GrpcClient.Web 的MVC5應用程式

 

建立一個空白專案

 

 

從 NuGet 安裝這三個 Packages:

 

Install-Package Google.Protobuf -Version 3.14.0
Install-Package Grpc.Net.Client -Version 2.34.0
Install-Package Grpc.Tools -Version 2.34.0

 

建立一個 protos 資料夾,將GrpcService專案中protos 資料夾的greet.proto,複製到GrpcClient.Web的protos 資料夾,點擊greet.proto右鍵選擇屬性,將gRPC Stub Classes的Server only改成Client only

 

建立三個資料夾Controllers、Models與Views

 

Models建立User

 

namespace GrpcClient.Web.Models
{
    public class User
    {
        public string Name { get; set; }

        public string Message { get; set; }
    }
}

 

Controllers建立HomeController

 

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GrpcClient.Web.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

 

建立一個Action,設定httpMethod為post

將主控台Program的程式,複製過來小小修改一下,修改成下面的程式

 

using Grpc.Net.Client;
using GrpcClient.Web.Models;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace GrpcClient.Web.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var model = new User();

            return View(model);
        }

        [HttpPost]
        public async Task<IActionResult> Index(User model)
        {
            using var channel = GrpcChannel.ForAddress("https://localhost:5001");

            var client = new Greeter.GreeterClient(channel);

            var reply = client.SayHello(new HelloRequest { Name = model.Name });

            model.Message = reply.Message;

            await channel.ShutdownAsync();

            return View(model);
        }
    }
}

 

在Views資料夾建立一個_ViewStart.cshtml

在Views資料夾建立一個_ViewImports.cshtml,加入下方設定

 

@using GrpcClient.Web
@using GrpcClient.Web.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

 

在Views資料夾建立一個Shared資料夾,並建立一個_Layout.cshtml

在Views資料夾建立一個Home資料夾,並建立一個Index.cshtml,加入下方程式碼

 

@model GrpcClient.Web.Models.User
@{
    ViewBag.Title = "Test";
}

<form asp-controller="Home" asp-action="Index" method="post">
    <label>請輸入你的名字</label>
    <input asp-for="Name" />
    <button type="submit">確定</button>
    <br />
    <br />
    <label>@Model.Message</label>
</form>

 

設定Startup檔

 

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace GrpcClient.Web
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}"
                );
            });
        }
    }
}

 

將啟動方案GrpcClient修改為GrpcClient.Web

 

執行

 

GrpcClient.Web

 

 

輸入名字,並點擊確定,就會收到GrpcService的回應

 

 

參考資料:

https://docs.microsoft.com/zh-tw/aspnet/core/grpc/?view=aspnetcore-5.0

https://grpc.io/docs/languages/csharp/

https://medium.com/@letienthanh0212/what-is-grpc-and-how-to-implement-grpc-with-asp-net-core-3-x-affe83686123

https://auth0.com/blog/implementing-microservices-grpc-dotnet-core-3/

Mark Lu