天天看點

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

Blazor WebAssembly是什麼

首先來說說WebAssembly是什麼,WebAssembly是一個可以使C#,Java,Golang等靜态強類型程式設計語言,運作在浏覽器中的标準,浏覽器廠商基于此标準實作執行引擎。

在實作了WebAssembly标準引擎之後,浏覽器中可以執行由其他語言編譯成的wasm子產品。使用強類型程式設計語言的好處顯而易見:

  • 可以選擇更多的語言,編寫前端邏輯
  • 靜态程式設計語言編譯成的位元組碼,相對于JS這種腳本語言執行效率更高
  • 可以使用靜态程式設計語言生态中的強大類庫

Blazor WebAssembly是dotnet版本的WebAssembly實作,微軟将dotnet運作時編譯成dotnet.wasm子產品,我們的程式編譯出來的dll檔案運作在此子產品上。

需要注意的是,Blazor WebAssembly是一個完完全全的前端架構,隻是邏輯代碼不再使用JS編寫,而是使用C#編寫。

Grpc Web是什麼

Grpc是一種與語言無關的的高性能遠端過程調用(RPC)架構。Grpc有以下優點

  • 現代高性能輕量級 RPC 架構。
  • 協定優先 API 開發,預設使用協定緩沖區,允許與語言無關的實作。
  • 可用于多種語言的工具,以生成強類型伺服器和用戶端。
  • 支援用戶端、伺服器和雙向流式處理調用。
  • 使用 Protobuf 二進制序列化減少對網絡的使用。

而Grpc Web是Grpc的前端實作版本,可以使浏覽器應用直接與Grpc互動。

有了Grpc Web,我們可以直接在Blazor WebAssembly中調用Grpc Server,而不用再通過傳統的Http請求方法調用。

代碼示範

GrpcServer

首先需要建立一個Grpc Server

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

然後為其引入 Grpc.AspNetCore.Web Nuget包,并開啟grpc web

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範
app.UseGrpcWeb(); // Must be added between UseRouting and UseEndpoints// Configure the HTTP request pipeline.app.MapGrpcService<GreeterService>().EnableGrpcWeb();           

複制

之後我們需要為Grpc Server開啟跨域設定,允許跨域通路

app.Use(async (context, next) =>{
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    context.Response.Headers.Add("Access-Control-Allow-Headers", "*");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH");
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Max-Age", "100000");
    context.Response.Headers.Add("Access-Control-Expose-Headers", "Grpc-Status,Grpc-Message,Grpc-Encoding,Grpc-Accept-Encoding");    
    if (context.Request.Method.ToUpper() == "OPTIONS")
    {        return;
    }    // Do work that can write to the Response.
    await next.Invoke();    // Do logging or other work that doesn't write to the Response.});           

複制

最終Program.cs的代碼如下

using GrpcService2.Services;var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();var app = builder.Build();
app.Use(async (context, next) =>{
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    context.Response.Headers.Add("Access-Control-Allow-Headers", "*");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH");
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Max-Age", "100000");
    context.Response.Headers.Add("Access-Control-Expose-Headers", "Grpc-Status,Grpc-Message,Grpc-Encoding,Grpc-Accept-Encoding");    if (context.Request.Method.ToUpper() == "OPTIONS")
    {        return;
    }    await next.Invoke();
});

app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();

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();           

複制

複制

Blazor WebAssembly

現在建立一個WebAssembly項目

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

為其引入以下nuget包

<ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.20.1" />
    <PackageReference Include="Grpc.Net.Client" Version="2.46.0" />
    <PackageReference Include="Grpc.Net.Client.Web" Version="2.46.0" />
    <PackageReference Include="Grpc.Tools" Version="2.46.1">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>           

複制

在其項目檔案中包含進proto檔案

<ItemGroup>
    <Protobuf Include="..\GrpcService2\Protos\*.proto" GrpcServices="Client" />
  </ItemGroup>           

複制

然後将GrpcClient注入容器

builder.Services.AddScoped(p =>
{
    var channel = GrpcChannel.ForAddress("https://localhost:7033/", new GrpcChannelOptions
    {
        HttpHandler = new GrpcWebHandler(new HttpClientHandler())
    });
    var client = new GrpcService2.Greeter.GreeterClient(channel);
    return client;
});           

複制

複制

修改Index.razor,讓其通路grpc server

@page "/"
@inject GrpcService2.Greeter.GreeterClient GreeterClient

<div>grpc web response @Message</div>

@code {
    public string Message { get; set; }
    protected override async Task OnInitializedAsync()
    {
        var reply = await GreeterClient.SayHelloAsync(new GrpcService2.HelloRequest { Name = "test" });
        Message = reply.Message;
    }
}           

複制

複制

最終效果如下

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

可以看到整個請求/渲染過程,使用的是C#代碼編寫的邏輯,沒用到js,原理是因為,blazor webassembly将我們的dotnet運作時,與我們的代碼編譯後的程式集,運作在了基于webassembly标準實作的浏覽器引擎中。

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

并且可以看到基于Grpc Web的請求響應體都使用的壓縮過的二進制形式。效率相對更高

Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範
Blazor WebAssembly + Grpc Web=未來?Blazor WebAssembly是什麼Grpc Web是什麼代碼示範

webassembly難道是未來?難道未來的某一天要和js say goodbye了嗎?