In Blazor WebAssembly in gRPC-Web

For single-page applications, gRPC-Web JSON-over-HTTP is a convenient, high-performance alternative.

If you already know everything about gRPC and gRPC-Web, you can jump to add gRPC service to a Blazor WebAssembly an application. If you just want some simple Blazor WebAssembly + gRPC-Web application, see the warehouse https://github.com/SteveSandersonMS/BlazorGrpcSamples.

status quo

With all other browser-based single-page application (SPA) technology, as in Blazor WebAssembly, the most common way to exchange data and trigger server-side operations are JSON-over-HTTP. It is very simple: the client using the HTTP method previously agreed HTTP request to a pre-agreed URL, and then the server performs an operation, using a pre-agreed HTTP status code and data format predetermined by JSON respond.

This method is usually very effective, so do people tend to live a fulfilling life. However, it also has two obvious weaknesses:

  • JSON is a very tedious data format, it does not optimize bandwidth.

  • There is no mechanism to ensure that all of these pre-agreed url, HTTP methods, status code, and so the details are virtually identical between the server and the client.

What is gRPC?

gRPC is a remote procedure call (RPC) mechanism, originally developed by Google. For SPA, you can be regarded as JSON-over-HTTP alternatives. It is directly fixes two vulnerabilities listed above:

  • It is optimized to minimize network traffic, effectively transmitted binary sequence of message

  • You can guarantee the existence of the server and client end-points at compile time, it agreed to send and receive data in the form, without specifying any URL, status codes, and so on.

This is how to do it?

To write gRPC service, you need to write a .protofile, which is a set of language-independent data describing RPC service and its shape. From here, you can use any language to generate a strong type of server and client classes to ensure compliance with your agreement at compile time. Then at run time, gRPC process (trans) sequence data and is valid format (default Protobuf) transmitted / received messages.

Another big benefit is that it is not REST, so you do not often argue with my colleagues and method which HTTP status code in your scene is the most happy and fortunate. It simply RPC, in our true feelings when he was a kid wants.

Why is not everyone using their gRPC in the SPA?

Traditionally, gRPC from the browser-based application is not possible because gRPC need HTTP / 2, and the browser does not expose any api, so JS, WASM code directly control the HTTP / 2 request.

But now there is a solution! GRPC gRPC-Web is an extension that enables GRPC compatible browser-based code (Technically, it is through the HTTP / 1.1 is a request to perform a way GRPC). gRPC-Web has not caught on, because so far there is not much server or client framework to provide support for it.

ASP.NET Core Version 3.0 provides a powerful gRPC support. Now, on this basis, we will provide a preview of support for gRPC-Web server and the client. If you want to learn more details, you can view all realize (in good pull request from James Newton-King of https://github.com/grpc/grpc-dotnet/pull/695 ).

Add gRPC service application to a Blazor WebAssembly

There is no project template in this area, so the gRPC support added to Blazor WebAssembly application requires many steps, this article is described in detail. But the good news is that you only need to do one of these settings. When you are finished with the start up and running, add more gRPC endpoints and call them is very simple. First, since gRPC-Web package has not yet released to NuGet.org, now you need to add two temporary package management source to obtain nightly preview. You can add in the root directory of your solution NuGet.configfiles. I hope that after a month or two is not necessary.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
    <clear />
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key="gRPC-nightly" value="https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev" />
    <add key="blazor-nightly" value="https://dotnetfeed.blob.core.windows.net/aspnet-blazor/index.json" />
  </packageSources>
</configuration>

Add gRPC services to a managed application deployed Blazor WebAssembly

If you are already hosting a Blazor WebAssembly application on ASP.NET Core server, by default, you have three projects: client, server and shared projects. I found the definition gRPC service is the most convenient place in the shared project, because it generates a class of server and client are available. First, edit your shared items .csprojto add the necessary gRPC package references:

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.11.2" />
    <PackageReference Include="Grpc.Net.Client" Version="2.27.0-dev202001100801" />
    <PackageReference Include="Grpc.Tools" Version="2.27.0-dev202001081219">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

If these packages can not be restored properly, be sure to add a nightly source.

You can now create a .protofile to define the service. For example, adding a named shared project greet.protofiles. It includes the following:

syntax = "proto3";
option csharp_namespace = "GrpcGreeter";
package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

For gRPC tool from here to generate server and client classes, go to the shared project .csprojand add the following:

  <ItemGroup>
    <Protobuf Include="greet.proto" />
  </ItemGroup>

At this point, the solution should be able to compile without error.

Public service from the server gRPC

In your server project, create a file named GreeterServicenew class contains the following:

using Grpc.Core;
using GrpcGreeter;

public class GreeterService : Greeter.GreeterBase
{
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        var reply = new HelloReply { Message = $"Hello from gRPC, {request.Name}!" };
        return Task.FromResult(reply);
    }
}

This class inherits from Greeter.GreeterBase, it is from the .protoautomatically generated file. So, when you add a new breakpoint to .protowhen you will have new method can be rewritten here to provide specific implementation.

The last part of the server is to use the new api to expose it as a gRPC-Webservice. To do this you need to reference a package, so your server project .csproj, add references to the following package:

<PackageReference Include="Grpc.AspNetCore" Version="2.27.0-dev202001100801" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.27.0-dev202001100801" />

Now, in your server's Startup.csfile, modify ConfigureServicesto add the following line:

  services.AddGrpc();

Note: If you only intend to open gRPC service, you may no longer need MVC controller, in this case, you can remove it from below services.AddMvc()and endpoints.MapDefaultControllerRoute().

Just app.AddRouting();add the following to the following, it will handle the incoming gRPC-web mapping request to the server to make it look like gRPC request:

  app.UseGrpcWeb();

Finally, app.UseEndpointsregister your gRPC-Web service class statement block, and use the following line of code at the top of the block form:

  endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();

In this way, your gRPC-Web server is ready!

Use gRPC services in the client

In your client project .csproj, you need to add the following two nightly package references:

<PackageReference Include="Grpc.Net.Client.Web" Version="2.27.0-dev202001100801" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Mono" Version="3.2.0-preview1.20052.1" />

The latter is a workaround to fix a problem in Blazor WebAssembly, the problem will be fixed in the next few weeks after the first preview. If these packages can not return to normal, be sure to add a nightly source.

Now set the dependency injection system your client application to be able to provide GreeterClientexamples. This will allow you to call gRPC service anywhere in the client application. In the client project Startup.csin the ConfigureServicesAdd the following methods:

services.AddSingleton(services =>
{
    // Create a gRPC-Web channel pointing to the backend server
    var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
    var baseUri = services.GetRequiredService<NavigationManager>().BaseUri;
    var channel = GrpcChannel.ForAddress(baseUri, new GrpcChannelOptions { HttpClient = httpClient });

    // Now we can instantiate gRPC clients for this channel
    return new Greeter.GreeterClient(channel);
});

Note that Greeter.GreeterClientfrom .proto fileyour generated code file. You do not have to manually implement it! But you also need to add the following statement to use, so that the code is compiled by:

using GrpcGreeter;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using Microsoft.AspNetCore.Components;
using System.Net.Http;

We are almost done! Now there is a working server, and hope to have a working client. We just need to call some gRPC from the UI service. For example, in your Index.razorfile, replace the following:

@page "/"
@using GrpcGreeter
@inject Greeter.GreeterClient GreeterClient

<h1>Invoke gRPC service</h1>

<p>
    <input @bind="yourName" placeholder="Type your name" />
    <button @οnclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>

Server response: <strong>@serverResponse</strong>

@code {
    string yourName = "Bert";
    string serverResponse;

    async Task GetGreeting()
    {
        var request = new HelloRequest { Name = yourName };
        var reply = await GreeterClient.SayHelloAsync(request);
        serverResponse = reply.Message;
    }
}

Now try it in your browser. The user interface looks like this:

If you request to view the browser developer tools network tab, you'll see it in the sending and receiving binary protobuf message:

Summary and examples

Now you have the foundation, if you wish, you can further use gRPC over all data exchanged between the server and the client. gRPC tool will generate all your class data transmission, to improve the efficiency of network traffic, and HTTP-over-JSON eliminate problems url, HTTP method, the sequence of state codes and the like.

There is a more detailed example ( https://github.com/SteveSandersonMS/BlazorGrpcSamples/tree/master/Hosted ), it is a complete Blazor WebAssembly managed application, use gRPC get "weather forecast" data. If you are interested in specific steps required to gRPC-Web-based solutions from the default json-based solutions to upgrade, see this accurately display the differences in contrast to change what I did ( HTTPS: // GitHub. COM / SteveSandersonMS / BlazorGrpcSamples / the commit / 72544c54085a35cd89aae20030d7f91d75317a2f ).

Add gRPC service into a separate application deployment Blazor WebAssembly

If you're building a pure stand-alone Blazor WebAssembly application, rather than hosted in ASP.NET Core, then we can not have what you would make any assumptions server (which means you only have to develop a client, while the server is scenarios developed by others). We can only assume that you want to call some compatibility with gRPC-Web service endpoint, they may be exposed on ASP.NET Core Services on other hosts, or around one another gRPC Envoy gRPC-Web services wrapper ( https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880 ). Here we only concern is to configure your Blazor WebAssembly application to use it. Set the client application and the majority of the steps above "managed the deployment of the" same situation. However, in some ways, it's a bit tricky, because we can not rely on some of the assumptions we have done in the "trusteeship" condition. Differences are as follows:

  • Access to and use .proto file

    Assuming your external gRPC service maintainers can provide this service for you defined .protofile. You can copy it to your client project, and .csprojadd a reference to it in the <Proto>entry. In order for the tool to work, you also need to add a reference package like this:

      <!-- Needed temporarily until the next Blazor WebAssembly preview release -->
      <PackageReference Include="Microsoft.AspNetCore.Blazor.Mono" Version="3.2.0-preview1.20052.1" />
    
      <!-- gRPC-Web packages -->
      <PackageReference Include="Google.Protobuf" Version="3.11.2" />
      <PackageReference Include="Grpc.Net.Client" Version="2.27.0-dev202001100801" />
      <PackageReference Include="Grpc.Net.Client.Web" Version="2.27.0-dev202001100801" />
      <PackageReference Include="Grpc.Tools" Version="2.27.0-dev202001081219">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      </PackageReference>
    
  • DI configure the client service

    And "managed hosting" The situation is similar, you will add the code to add Startup.cs gRPC-Web Client service. The main difference here is that you must know what Base URL for accessing external services, because we can no longer assume it's the same with Base URL Base URL hosting your client application service side. Therefore, your DI service registration may look more like the following:

    services.AddSingleton(services =>
    {
    #if DEBUG
        var backendUrl = "https://localhost:5001"; // Local debug URL
    #else
        var backendUrl = "https://some.external.url:12345"; // Production URL
    #endif
    
        // Now we can instantiate gRPC clients for this channel
        var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
        var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient });
        return new Greeter.GreeterClient(channel);
    });
    

    This URL will vary depending on whether you are building in debug mode.

Summary and examples

That's it! Now, Blazor WebAssembly application you can use to deploy independent external gRPC-Web services. For the complete sample run, the following is an example of independent application ( https://github.com/SteveSandersonMS/BlazorGrpcSamples/tree/master/Standalone), it calls a gRPC-Web service on an external URL. This example comes with a practical gRPC-Web server for testing, but you can consider it separately. If you want to see exactly what I changed, here is the difference with the default project template output ( https://github.com/SteveSandersonMS/BlazorGrpcSamples/commit/d6ec609f2b7e6591958d38e4a207c9b4f52f0feb).

Your feedback request

If you want to learn more about gRPC, please refer to the ASP.NET Core gRPC document. Ask us propose you gRPC-Web views and experience feedback, as this will help us to choose how and whether gRPC-Web as a standard feature in future versions of ASP.NET Core manipulation. You can comment here, or release issue with the title "feedback" on GitHub.

Translated from the original: https: //blog.stevensanderson.com/2020/01/15/2020-01-15-grpc-web-in-blazor-webassembly

related articles:

Recently, the observation and analysis of the .NET platform SkyWalking automatic probe (SkyAPM-dotnet) has supported the link trace acquisition grpc-dotnet remote calls are welcome to use! If you like it, please give a star!

Project address: https: //github.com/SkyAPM/SkyAPM-dotnet

Released 1535 original articles · won praise 586 · Views 2.37 million +

Guess you like

Origin blog.csdn.net/sD7O95O/article/details/104079137