【gRPC】使用ASP.NET Core 實作 gRPC
什麼是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://auth0.com/blog/implementing-microservices-grpc-dotnet-core-3/