Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hakenr/BlazorGrpcWebCodeFirst
Sample implementation of gRPC-Web code-first approach in Blazor WebAssembly ASP.NET Core hosted project.
https://github.com/hakenr/BlazorGrpcWebCodeFirst
blazor-webassembly code-first grpc-web
Last synced: 18 days ago
JSON representation
Sample implementation of gRPC-Web code-first approach in Blazor WebAssembly ASP.NET Core hosted project.
- Host: GitHub
- URL: https://github.com/hakenr/BlazorGrpcWebCodeFirst
- Owner: hakenr
- Created: 2020-04-14T23:10:15.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-08-03T09:28:17.000Z (over 1 year ago)
- Last Synced: 2024-04-07T15:33:48.498Z (7 months ago)
- Topics: blazor-webassembly, code-first, grpc-web
- Language: HTML
- Size: 337 KB
- Stars: 39
- Watchers: 4
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 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:
* [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web) (prerelease)
* [protobuf-net.Grpc.AspNetCore](https://www.nuget.org/packages/protobuf-net.Grpc.AspNetCore/)Register `CodeFirstGrpc()` and `GrpcWeb()` services in `Startup.cs` ConfigureServices() method:
```csharp
services.AddCodeFirstGrpc(config => { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });
```Add `GrpcWeb` middleware in between `UseRouting()` and `UseEndpoints()`:
```csharp
app.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });
```## 2. Blazor.Shared - Define the service contract (code-first)
Add [System.ServiceModel.Primitives](https://www.nuget.org/packages/System.ServiceModel.Primitives/) NuGet package.Define the interface of your service:
```csharp
[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:```csharp
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`:
```csharp
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService();
// ...
}
```## 4. Blazor.Client (Blazor Web Assembly) - consume the service
Add NuGet packages:
* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client)
* [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web) (prerelease)
* [protobuf-net.Grpc](https://www.nuget.org/packages/protobuf-net.Grpc)### 4A. Direct consumption of the service
Consume the service in your razor file:```csharp
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();
this.result = await testFacade.DoSomething(request);
}
```### 4B. Consumption via dependency injection
Register a GrpcChannel in your `Program.cs` (or `Startup.cs:ConfigureServices()`)
```csharp
builder.Services.AddSingleton(services =>
{
// Get the service address from appsettings.json
var config = services.GetRequiredService();
var backendUrl = config["BackendUrl"];// If no address is set then fallback to the current webpage URL
if (string.IsNullOrEmpty(backendUrl))
{
var navigationManager = services.GetRequiredService();
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).
```csharp
builder.Services.AddTransient(services =>
{
var grpcChannel = services.GetRequiredService();
return grpcChannel.CreateGrpcService();
});
```And now you can consume the services whereever needed (e.g. from .razor file):
```csharp
@inject IMyService 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:
* https://github.com/havit/NewProjectTemplate-Blazor# References, Credits
* [Steve Sanderson: Using gRPC-Web with Blazor WebAssembly](https://blog.stevensanderson.com/2020/01/15/2020-01-15-grpc-web-in-blazor-webassembly/)
* [Use gRPC in browser apps | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/grpc/browser)
* [protobuf-net.Grpc - Getting Started](https://protobuf-net.github.io/protobuf-net.Grpc/gettingstarted)
* https://github.com/grpc/grpc-dotnet/blob/master/examples/Blazor/Client/Program.cs
* credits to @dani-herrera-udg for upgrading to .NET 6# Known Issues
* https://github.com/dotnet/runtime/issues/62054 - may be hitting GC bug in .NET6