Skip to content

Sample implementation of gRPC-Web code-first approach in Blazor WebAssembly ASP.NET Core hosted project.

Notifications You must be signed in to change notification settings

hakenr/BlazorGrpcWebCodeFirst

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Blazor WebAssembly with gRPC-Web code-first approach

Do you like WCF-like approach and need to cover communication in between ASP.NET Core service and Blazor WebAssembly client? Use code-first with gRPC-Web! You can try the it right now by following a few simple steps (commit):

1. Blazor.Server - Prepare the ASP.NET Core host

Add NuGet packages:

Register CodeFirstGrpc() and GrpcWeb() services in Startup.cs ConfigureServices() method:

services.AddCodeFirstGrpc(config => { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });

Add GrpcWeb middleware in between UseRouting() and UseEndpoints():

app.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });

2. Blazor.Shared - Define the service contract (code-first)

Add System.ServiceModel.Primitives NuGet package.

Define the interface of your service:

[ServiceContract] public interface IMyService { Task DoSomething(MyServiceRequest request); } [DataContract] public class MyServiceResult { [DataMember(Order = 1)] public string NewText { get; set; } [DataMember(Order = 2)] public int NewValue { get; set; } } [DataContract] public class MyServiceRequest { [DataMember(Order = 1)] public string Text { get; set; } [DataMember(Order = 2)] public int Value { get; set; } }

3. Blazor.Server - Implement and publish the service

Implement your service:

public class MyService : IMyService { public Task DoSomething(MyServiceRequest request) { return Task.FromResult(new MyServiceResult() { NewText = request.Text + " from server", NewValue = request.Value + 1 }); } }

Publish the service in Startup.cs:

app.UseEndpoints(endpoints => { endpoints.MapGrpcService<MyService>(); // ... }

4. Blazor.Client (Blazor Web Assembly) - consume the service

Add NuGet packages:

4A. Direct consumption of the service

Consume the service in your razor file:

var handler = new Grpc.Net.Client.Web.GrpcWebHandler(Grpc.Net.Client.Web.GrpcWebMode.GrpcWeb, new HttpClientHandler()); using (var channel = Grpc.Net.Client.GrpcChannel.ForAddress("https://localhost:44383/", new Grpc.Net.Client.GrpcChannelOptions() { HttpClient = new HttpClient(handler) })) { var testFacade = channel.CreateGrpcService<IMyService>(); this.result = await testFacade.DoSomething(request); }

4B. Consumption via dependency injection

Register a GrpcChannel in your Program.cs (or Startup.cs:ConfigureServices())

builder.Services.AddSingleton(services => { // Get the service address from appsettings.json var config = services.GetRequiredService<IConfiguration>(); var backendUrl = config["BackendUrl"]; // If no address is set then fallback to the current webpage URL if (string.IsNullOrEmpty(backendUrl)) { var navigationManager = services.GetRequiredService<NavigationManager>(); backendUrl = navigationManager.BaseUri; } // Create a channel with a GrpcWebHandler that is addressed to the backend server. // // GrpcWebText is used because server streaming requires it. If server streaming is not used in your app // then GrpcWeb is recommended because it produces smaller messages. var httpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()); return GrpcChannel.ForAddress( backendUrl, new GrpcChannelOptions { HttpHandler = httpHandler, //CompressionProviders = ..., //Credentials = ..., //DisposeHttpClient = ..., //HttpClient = ..., //LoggerFactory = ..., //MaxReceiveMessageSize = ..., //MaxSendMessageSize = ..., //ThrowOperationCanceledOnCancellation = ..., }); });

Register the individual services (you might want to extract the "logic" to an extension method for better readability).

builder.Services.AddTransient<IMyService>(services => { var grpcChannel = services.GetRequiredService<GrpcChannel>(); return grpcChannel.CreateGrpcService<IMyService>(); });

And now you can consume the services whereever needed (e.g. from .razor file):

@injectIMyService MyService @code { async Task Submit() { this.result = await MyService.DoSomething(request); } }

Advanced scenarios

For more advanced usage with error-handling, authentication + authorization and more, see our Havit.Blazor project template:

References, Credits

Known Issues

About

Sample implementation of gRPC-Web code-first approach in Blazor WebAssembly ASP.NET Core hosted project.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •