欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ASP.NET Core中Grpc通信的簡單用法

 更新時間:2022年07月25日 09:41:21   作者:奮斗的大橙子  
這篇文章介紹了ASP.NET Core中Grpc通信的簡單用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

目錄:

  • 一、簡單介紹DotnetCore3.0如何將.proto文件生成對應的服務端和客戶端類
  • 二、介紹如何在服務端使用Grpc,以及Grpc需要的條件(HTTP2、TLS)
  • 三、介紹如何創(chuàng)建GrpcClient,以及Grpc通訊的四種模式
  • 四、舉例如何使用Grpc

一、如何使用protobuf生成服務類

Grpc中使用協(xié)議緩沖區(qū) (protobuf) 用作接口設計語言 (IDL),它的主要內(nèi)容包含:

  • GRPC 服務的定義。
  • 客戶端和服務器之間發(fā)送的消息。

Grpc.Tools 這個工具,在每次編譯的時候,都能將.proto文件生成為對于的cs文件。 服務端和客戶端都需要添加。Grpc.AspNetCore這個包會對Grpc.Tools 進行使用。引用了這個包之后。還有注意在Server和Client,都要在對應.csproj下面,修改GrpcServices這個配置的值,如果是服務端就寫Server,如果是客戶端就寫Client。

<ItemGroup>  
    <Protobuf Include="Protos\xxxx.proto" GrpcServices="Server" />
</ItemGroup>
 
<ItemGroup>  
    <Protobuf Include="Protos\xxxx.proto" GrpcServices="Client" />
</ItemGroup>

二、服務端使用Grpc

1.添加引用

需要添加 Grpc.AspNetCore 的引用

2.配置Grpc

在Startup.cs中需要配置如下信息:

①ConfigureServices 中需要配置

services.AddGrpc();

②Configure 中需要配置endpoints

app.UseEndpoints(endpoints =>
{
    // 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
    endpoints.MapGrpcService<GreeterService>();
});

3.Kestrel的配置

Grpc中的endpoints需要下面的支持:

HTTP/2

gRPC 要求 HTTP/2。gRPC for ASP.NET Core 驗證HttpRequest為HTTP/2。在大多數(shù)現(xiàn)代操作系統(tǒng)上,Kestrel支持 HTTP/2。默認情況下,Kestrel 終結(jié)點配置為支持 HTTP/1.1 和 HTTP/2 連接。

傳輸安全性Transport Layer Security (TLS).

用于 gRPC 的 Kestrel 終結(jié)點應使用 TLS 進行保護。

在開發(fā)版中,將在存在 ASP.NET Core 開發(fā)證書https://localhost:5001時,自動創(chuàng)建一個使用 TLS 保護的終結(jié)點。不需要配置。https前綴驗證 Kestrel 終結(jié)點是否正在使用 TLS。

在生產(chǎn)環(huán)境如果使用TLS中,必須顯式配置 TLS。

兩種方式配置對應的TLS:

1.在AppSettings下面添加配置節(jié)點:

{
  "Kestrel": {
    "Endpoints": {
      "HttpsInlineCertFile": {
        "Url": "https://localhost:5001",
        "Protocols": "Http2",
        "Certificate": {
          "Path": "<path to .pfx file>",
          "Password": "<certificate password>"
        }
      }
    }
  }
}

2.直接在代碼中添加

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.Listen(IPAddress.Any, 5001, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    listenOptions.UseHttps("<path to .pfx file>",
                        "<certificate password>");
                });
            });
            webBuilder.UseStartup<Startup>();
        });

此外TLS不僅僅適用于Client和Server間的安全傳輸,還可以用于服務協(xié)商。

我在看官網(wǎng)的關于服務協(xié)商時候,有些發(fā)懵,因為又說了grpc 需要Http/2 、又需要TLS,但是后面又說在不配置TLS的endpoint的時候...... 那么到底是需要TLS還是不需要TLS,Grpc到底是僅僅支持HTTP2還是會兼容HTTP1?

首先要明確幾個概念:

  • 什么是EndPoint
  • 什么是Grpc endpoint
  • 什么是TLS

TLS 和 HTTP1、HTTP2

以下是我的理解:

Endpoint是一個大概念,不僅僅是grpc有endpoint,以前我們用的webservice、wcf都有,他可以是HTTP1的,也可以是HTTP2的,也可以都支持。僅僅是當我們要用Grpc的時候我們需要使用HTTP2協(xié)議。

TLS是一種安全協(xié)議,是在傳輸層上的安全協(xié)議,具體是什么樣的可以不用了解,只是在.Net Core 中配置TLS,不僅僅作用于安全傳輸,還有作用于協(xié)議的選擇,當我們的endpoint使用的是HTTP2,且不用TLS的時候,我們需要配置我們的Kestrel服務器的ListenOptions.Protocols 必須設置為HttpProtocols.Http2 ,換句話說 如果ListenOptions.Protocols= HttpProtocols.Http1AndHttp2,那么就不能使用TLS。

總結(jié)一下就是:

你配置你的Kestrel 為使用HTTP2協(xié)議的時候,你可以使用TLS作為安全傳輸,也可以不用

你配置你的Kestrel 為使用兼容HTTP1協(xié)議的時候,那么你就不能用TLS

那么對于GPRC來講,他的endpoint 必須使用HTTP2協(xié)議,TLS也不是必須要配置的。

4.將Grpc像Api一樣提供出去

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
        });
    }
}
  • ①繼承一下生成出來的抽象類 Greeter.GreeterBase
  • ②根據(jù)自己的需要,依賴注入一些必要的Service類
  • ③實現(xiàn)生成出來的Virtual方法

備注:

  • 1.發(fā)生的問題

  • 2.Status(StatusCode=Internal, Detail="Error starting gRPC call: The SSL connection could not be established, see inner exception.")

https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0

  • 3.Grpc.Core.RpcException:“Status(StatusCode=Internal, Detail="Bad gRPC response. Response protocol downgraded to HTTP/1.0.")”

先按照下面的做

https://github.com/grpc/grpc-dotnet/issues/654

如果不行的話,檢查一下是否本地一直在開著抓包工具之類的代理軟件,我之前一直不行,是因為本地運行著Fiddler

三、客戶端使用Grpc

1.創(chuàng)建Gprc客戶端

和上面不一樣,grpc client 是通過 xxx.proto 文件生成的具體的類型。里面包含了我們要調(diào)用的所有的方法。一般情況下,我們都是創(chuàng)建一個Channel類,然后通過Channel類在創(chuàng)建一個Client。

如下圖所示。

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greet.GreeterClient(channel);

ForAddress方法:

注:

gRPC的Channel維持了一個到遠程服務的長連接。

客戶端對象可以重用相同的通道。

與調(diào)用遠程方法相比,創(chuàng)建通道是一項昂貴的操作,因此通常應該為盡可能多的調(diào)用重用單個通道。

2.Grpc方法調(diào)用

Grpc具有多種不同的方式:

  •   Unary  (一元模式)
  •   Server streaming (服務器流)
  •   Client streaming (客戶端流)
  •   Bi-directional streaming (雙向流)

① Unary方式

從客戶端發(fā)送請求到服務端開始,服務端響應請求回來結(jié)束。每一個Unary 服務都會從*.proto文件中生成兩個具體的調(diào)用方法,一個異步方法,一個同步方法。例如下面的代碼:

var reply1 = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
var reply2 =  client.SayHello(new HelloRequest { Name = "GreeterClient" });

②Server streaming 方式

從客戶端發(fā)送請求到服務端開始,利用ResponseStream.MoveNext()方法讀取服務端返回的數(shù)據(jù),知道ResponseStream.MoveNext() 返回false說明讀取結(jié)束。

var client = new Greet.GreeterClient(channel);
using (var call = client.SayHellos(new HelloRequest { Name = "World" }))
{
    while (await call.ResponseStream.MoveNext())
    {
        Console.WriteLine("Greeting: " + call.ResponseStream.Current.Message);
        // "Greeting: Hello World" is written multiple times
    }
}
 
//或者C# 8以上通過await foreach來處理返回信息
using (var call = client.SayHellos(new HelloRequest { Name = "World" }))
{
    await foreach (var response in call.ResponseStream.ReadAllAsync())
    {
        Console.WriteLine("Greeting: " + response.Message);
        // "Greeting: Hello World" is written multiple times
    }
}

③Client streaming 方式

客戶端流調(diào)用不需要在客戶端發(fā)送請求之后開始,客戶端可以選擇發(fā)送帶有RequestStream.WriteAsync的發(fā)送消息,當客戶端完成發(fā)送消息請求流時。調(diào)用CompleteAsync來通知服務,當服務返回響應消息時,調(diào)用結(jié)束。

var client = new Counter.CounterClient(channel);
using (var call = client.AccumulateCount())
{
    //調(diào)用三次
    for (var i = 0; i < 3; i++)
    {
        await call.RequestStream.WriteAsync(new CounterRequest { Count = 1 });
    }
    //通知服務寫好了
    await call.RequestStream.CompleteAsync();
    //獲取返回結(jié)果
    var response = await call;
    Console.WriteLine($"Count: {response.Count}");
    // Count: 3
}

④Bi-directional streaming call 方式

相當于②和③的結(jié)合,也不需要等待客戶端發(fā)送完請求,使用RequestStream.WriteAsync寫入消息,通過ResponseStream.MoveNext()或者ResponseStream.ReadAllAsync()讀取服務端返回的數(shù)據(jù)。當服務端不在返回的時候,結(jié)束請求。

using (var call = client.Echo())
{
    Console.WriteLine("Starting background task to receive messages");
    var readTask = Task.Run(async () =>
    {
        await foreach (var response in call.ResponseStream.ReadAllAsync())
        {
            Console.WriteLine(response.Message);
            // Echo messages sent to the service
        }
    });
 
    Console.WriteLine("Starting to send messages");
    Console.WriteLine("Type a message to echo then press enter.");
    while (true)
    {
        var result = Console.ReadLine();
        if (string.IsNullOrEmpty(result))
        {
            break;
        }
 
        await call.RequestStream.WriteAsync(new EchoMessage { Message = result });
    }
 
    Console.WriteLine("Disconnecting");
    await call.RequestStream.CompleteAsync();
    await readTask;
}

此外這里補充一下幾種方式適用的場景

  • (1) 簡單模式(Simple RPC)

這種模式最為傳統(tǒng),即客戶端發(fā)起一次請求,服務端響應一個數(shù)據(jù),這和大家平時熟悉的RPC沒有什么大的區(qū)別,所以不再詳細介紹。

  • (2) 服務端數(shù)據(jù)流模式(Server-side streaming RPC)

這種模式是客戶端發(fā)起一次請求,服務端返回一段連續(xù)的數(shù)據(jù)流。典型的例子是客戶端向服務端發(fā)送一個股票代碼,服務端就把該股票的實時數(shù)據(jù)源源不斷的返回給客戶端。

  • (3) 客戶端數(shù)據(jù)流模式(Client-side streaming RPC)

與服務端數(shù)據(jù)流模式相反,這次是客戶端源源不斷的向服務端發(fā)送數(shù)據(jù)流,而在發(fā)送結(jié)束后,由服務端返回一個響應。典型的例子是物聯(lián)網(wǎng)終端向服務器報送數(shù)據(jù)。

  • (4) 雙向數(shù)據(jù)流模式(Bidirectional streaming RPC)

顧名思義,這是客戶端和服務端都可以向?qū)Ψ桨l(fā)送數(shù)據(jù)流,這個時候雙方的數(shù)據(jù)可以同時互相發(fā)送,也就是可以實現(xiàn)實時交互。典型的例子是聊天機器人。

四、舉例使用Grpc創(chuàng)建一個服務

1.創(chuàng)建兩個控制臺程序,分別為服務端和客戶端

2.在服務端創(chuàng)建服務

①在GrpcService中引入Grpc.AspNetCore包,此包會在編譯的時候,將.proto文件生成對應的服務端grpc服務代碼。

.net core需要自己去生成,3.0以后已經(jīng)在上面的包中集成的生成的功能,只要生成代碼就會調(diào)用Grpc.Tools和Google.Protobuf去產(chǎn)生對應的cs文件

②創(chuàng)建一個proto文件

syntax = "proto3";
 
option csharp_namespace = "GrpcService";
 
package Hello;
 
service Hello {
  //通過一元方式傳輸
  rpc SayHello (HelloRequest) returns (HelloReply);
  //通過客戶端流的方式傳輸
  rpc SayHelloClientStream (stream HelloRequest) returns (HelloReply);
  //通過服務端流的方式傳輸
  rpc SayHelloServerStream (HelloRequest) returns (stream HelloReply);
  //通過雙向流的方式傳輸
  rpc SayHelloStream (stream HelloRequest) returns (stream HelloReply);
}
 
message HelloRequest {
  string name = 1;
}
 
message HelloReply {
  string message = 1;
}

并修改對應的服務端csproj文件,將該proto文件加入到項目中,否則不會生成服務端代碼。

<ItemGroup>   
     <Protobuf Include="Hello.proto" GrpcServices="Server" />
</ItemGroup>

③創(chuàng)建一個HelloService類,繼承自生成出來的抽象類XXXBase,然后可以重寫對應我們聲明的方法,以便于提供客戶端訪問。

注:xxx.xxxBase 可能在繼承的時候顯示不存在,那是因為沒有②之后沒有進行編譯,編譯之后就能生成了。

public class HelloService : Hello.HelloBase
{
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = "Response:" + request.Name
        });
    }
 
    public override async Task<HelloReply> SayHelloClientStream(IAsyncStreamReader<HelloRequest> requestStream, ServerCallContext context)
    {
 
        var current = new HelloRequest();
        while (await requestStream.MoveNext())
        {
            current = requestStream.Current;
        }
 
        var task = new Task<HelloReply>(() =>
        {
            var reply = new HelloReply()
            {
                Message = "Response:" + current.Name
            };
            return reply;
        });
 
        task.Start();
 
        var result = await task;
 
        return result;
    }
 
    public override async Task SayHelloServerStream(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        await responseStream.WriteAsync(new HelloReply() { Message = "Response:" + request.Name });
 
    }
 
    public override async Task SayHelloStream(IAsyncStreamReader<HelloRequest> requestStream,
        IServerStreamWriter<HelloReply> responseStream,
        ServerCallContext context)
    {
        while (await requestStream.MoveNext())
        {
            await responseStream.WriteAsync(new HelloReply() { Message = "Response:" + requestStream.Current.Name });
        }
    }
}

④因為是服務端,一旦實現(xiàn)了所有的方法,還需要啟動一個gRPC服務器,這樣客戶端才可以使用服務。

可以采用兩種方式來持久化服務,監(jiān)聽端口,處理請求:

a.使用Grpc.Core里面的Server (適用于.net core 3.0以下版本)

b.配置startup.cs中的ConfigureServices添加服務,Configure方法中配置終結(jié)點,并且配置對應的Kestrel服務器

第一種方式:

class Program
{
    private static Server _server;
 
    static void Main(string[] args)
    {
        _server = new Server
        {
            Services = { Hello.BindService(new HelloService()) },
            //這里使用的是不安全的方式
            Ports = { new ServerPort("localhost", 50001, ServerCredentials.Insecure) }
        };
        _server.Start();
 
        Console.WriteLine("Listen Port 50001");
        Console.ReadKey();
 
        _server?.ShutdownAsync().Wait();
    }
}

第二種方式:

class Program
{
    static void Main(string[] args)
    {
        #region 使用Kestrel服務器
        CreateHostBuilder(args).Build().Run();
        #endregion
    }
 
    public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
          .ConfigureWebHostDefaults(webBuilder =>
          {
              webBuilder.ConfigureKestrel(options =>
              {
                    // Setup a HTTP/2 endpoint without TLS.
                    options.ListenLocalhost(50001, o => o.Protocols =
                      HttpProtocols.Http2);
              });
 
              webBuilder.UseStartup<Startup>();
          });
}

Startup.cs

public class Startup
{   
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }
 
    // 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.UseRouting();
 
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<HelloService>();
 
            endpoints.MapGet("/", async context =>
            {
                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");
            });
        });
    }
}

3.在GrpcClient中引入如下包

①添加相關的依賴包

Install-Package Grpc.Net.Client

Install-Package Google.Protobuf

Install-Package Grpc.Tools

②添加之后,把服務端的proto文件一樣復制一份到客戶端,并在csproj下面追加如下的代碼,并編譯一次:

<ItemGroup>    
    <Protobuf Include="Hello.proto" GrpcServices="Client" />  
</ItemGroup>

③編寫客戶端調(diào)用的具體內(nèi)容

class Program
{
    static async Task Main(string[] args)
    {
        // This switch must be set before creating the GrpcChannel/HttpClient.
        AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
 
        var channel = GrpcChannel.ForAddress("http://localhost:50001");
        var helloClient = new Hello.HelloClient(channel);
 
        //一元調(diào)用(同步方法)
        var reply = helloClient.SayHello(new HelloRequest { Name = "一元同步調(diào)用" });
        Console.WriteLine($"{reply.Message}");
 
        //一元調(diào)用(異步方法)
        var reply2 = helloClient.SayHelloAsync(new HelloRequest { Name = "一元異步調(diào)用" }).GetAwaiter().GetResult();
        Console.WriteLine($"{reply2.Message}");
 
        //服務端流
        var reply3 = helloClient.SayHelloServerStream(new HelloRequest { Name = "服務端流" });
        while (await reply3.ResponseStream.MoveNext())
        {
            Console.WriteLine(reply3.ResponseStream.Current.Message);
        }
 
        //客戶端流
        using (var call = helloClient.SayHelloClientStream())
        {  
            await call.RequestStream.WriteAsync(new HelloRequest { Name = "客戶端流" + i.ToString() });
            await call.RequestStream.CompleteAsync();
            var reply4 = await call;
            Console.WriteLine($"{reply4.Message}");
        }
 
        //雙向流
        using (var call = helloClient.SayHelloStream())
        {
            Console.WriteLine("Starting background task to receive messages");
            var readTask = Task.Run(async () =>
            {
                await foreach (var response in call.ResponseStream.ReadAllAsync())
                {
                    Console.WriteLine(response.Message);
                }
            });
             
            for (var i = 0; i < 3; i++)
            {
                await call.RequestStream.WriteAsync(new HelloRequest { Name = "雙向流" + i.ToString()});
            }
 
            await call.RequestStream.CompleteAsync();
            await readTask;
        }
        Console.ReadKey();
    }
}

執(zhí)行:

這里要注意一段代碼AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true),如果不使用這段代碼,并且channel當中還是http的話,那么就會出現(xiàn)下面的異常:

到此這篇關于ASP.NET Core中Grpc通信基礎的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • .Net Core3 用Windows 桌面應用開發(fā)Asp.Net Core網(wǎng)站

    .Net Core3 用Windows 桌面應用開發(fā)Asp.Net Core網(wǎng)站

    這篇文章主要介紹了.Net Core3 用Windows 桌面應用開發(fā)Asp.Net Core網(wǎng)站,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 解析微信支付的實現(xiàn)方法(.NET版)

    解析微信支付的實現(xiàn)方法(.NET版)

    由于微信的廣泛利用,基于微信開發(fā)的一系列也應運而生,這篇文章主要介紹了解析微信支付的實現(xiàn)方法(.NET版),有興趣的可以了解一下。
    2016-11-11
  • .NET使用System.Timers.Timer類實現(xiàn)程序定時執(zhí)行

    .NET使用System.Timers.Timer類實現(xiàn)程序定時執(zhí)行

    這篇文章介紹了.NET使用System.Timers.Timer類實現(xiàn)程序定時執(zhí)行的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • ASP.NET中使用IFRAME建立類Modal窗口

    ASP.NET中使用IFRAME建立類Modal窗口

    ASP.NET中使用IFRAME建立類Modal窗口...
    2006-09-09
  • Entity Framework Core表名映射

    Entity Framework Core表名映射

    這篇文章介紹了Entity Framework Core實現(xiàn)表名映射的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • 解決VS2012 Express的There was a problem sending the command to the program問題

    解決VS2012 Express的There was a problem sending the command to

    安裝Visual Studio 2012 Express之后,雙擊打開web.config文件時經(jīng)常出現(xiàn)“There was a problem sending the command to the program”的錯誤,然后VS2012 Express打開了,但web.config文件沒打開,需要再次雙擊web.config文件才能打開。很是煩人
    2013-02-02
  • 三種asp.net頁面跳轉(zhuǎn)的方法

    三種asp.net頁面跳轉(zhuǎn)的方法

    跳轉(zhuǎn)頁面是大部編輯語言中都會有的,下面我們來分別介紹一下關于.net中response.redirect sever.execute server.transfer三種頁面跳轉(zhuǎn)的方法,,需要的朋友可以參考下
    2015-10-10
  • CSRF在ASP.NET Core中的處理方法詳解

    CSRF在ASP.NET Core中的處理方法詳解

    這篇文章主要給大家介紹了關于CSRF在ASP.NET Core中的處理方法,文中通過圖文以及示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧
    2018-07-07
  • asp.net 在線編輯word文檔 可保存到服務器

    asp.net 在線編輯word文檔 可保存到服務器

    使用說明:該方法只在office xp 和 2003上 測試通過,2000及以下 版本沒試。
    2010-01-01
  • 淺談.Net Core 認證系統(tǒng)源碼解析

    淺談.Net Core 認證系統(tǒng)源碼解析

    這篇文章主要介紹了淺談.Net Core 認證系統(tǒng)源碼解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12

最新評論