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
然後為其引入 Grpc.AspNetCore.Web Nuget包,並開啟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專案
為其引入以下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; } }
最終效果如下
可以看到整個請求/渲染過程,使用的是C#程式碼編寫的邏輯,沒用到js,原理是因為,blazor webassembly將我們的dotnet執行時,與我們的程式碼編譯後的程式集,執行在了基於webassembly標準實現的瀏覽器引擎中。
並且可以看到請求響應體都使用的壓縮過的二進位制形式。效率相對更高
webassembly難道是未來?難道未來的某一天要和js say goodbye了嗎?