{"id":13466158,"url":"https://github.com/hakenr/BlazorGrpcWebCodeFirst","last_synced_at":"2025-03-25T21:31:23.965Z","repository":{"id":44164477,"uuid":"255748984","full_name":"hakenr/BlazorGrpcWebCodeFirst","owner":"hakenr","description":"Sample implementation of gRPC-Web code-first approach in Blazor WebAssembly ASP.NET Core hosted project.","archived":false,"fork":false,"pushed_at":"2023-08-03T09:28:17.000Z","size":345,"stargazers_count":43,"open_issues_count":0,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-05T01:43:13.470Z","etag":null,"topics":["blazor-webassembly","code-first","grpc-web"],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hakenr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-14T23:10:15.000Z","updated_at":"2024-12-23T07:44:46.000Z","dependencies_parsed_at":"2024-07-31T15:12:36.126Z","dependency_job_id":null,"html_url":"https://github.com/hakenr/BlazorGrpcWebCodeFirst","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hakenr%2FBlazorGrpcWebCodeFirst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hakenr%2FBlazorGrpcWebCodeFirst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hakenr%2FBlazorGrpcWebCodeFirst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hakenr%2FBlazorGrpcWebCodeFirst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hakenr","download_url":"https://codeload.github.com/hakenr/BlazorGrpcWebCodeFirst/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245547388,"owners_count":20633362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blazor-webassembly","code-first","grpc-web"],"created_at":"2024-07-31T15:00:40.056Z","updated_at":"2025-03-25T21:31:23.642Z","avatar_url":"https://github.com/hakenr.png","language":"HTML","readme":"# Blazor WebAssembly with gRPC-Web code-first approach\nDo 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 (\u003ca href=\"https://github.com/hakenr/BlazorGrpcWebCodeFirst/commit/e2bbbbb0aa8b9c9709145e271ee25cb41a4effae\"\u003ecommit\u003c/a\u003e):\n## 1. Blazor.Server - Prepare the ASP.NET Core host\nAdd NuGet packages:\n* [Grpc.AspNetCore.Web](https://www.nuget.org/packages/Grpc.AspNetCore.Web) (prerelease)\n* [protobuf-net.Grpc.AspNetCore](https://www.nuget.org/packages/protobuf-net.Grpc.AspNetCore/)\n\nRegister `CodeFirstGrpc()` and `GrpcWeb()` services in `Startup.cs` ConfigureServices() method:\n\n```csharp\nservices.AddCodeFirstGrpc(config =\u003e { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });\n```\n\nAdd `GrpcWeb` middleware in between `UseRouting()` and `UseEndpoints()`:\n\n```csharp\napp.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });\n```\n\n## 2. Blazor.Shared - Define the service contract (code-first)\nAdd [System.ServiceModel.Primitives](https://www.nuget.org/packages/System.ServiceModel.Primitives/) NuGet package.\n\nDefine the interface of your service:\n\n```csharp\n[ServiceContract]\npublic interface IMyService\n{\n\tTask DoSomething(MyServiceRequest request);\n\n}\n\n[DataContract]\npublic class MyServiceResult\n{\n\t[DataMember(Order = 1)]\n\tpublic string NewText { get; set; }\n\n\t[DataMember(Order = 2)]\n\tpublic int NewValue { get; set; }\n}\n\n[DataContract]\npublic class MyServiceRequest\n{\n\t[DataMember(Order = 1)]\n\tpublic string Text { get; set; }\n\n\t[DataMember(Order = 2)]\n\tpublic int Value { get; set; }\n}\n```\n\n## 3. Blazor.Server - Implement and publish the service\nImplement your service:\n\n```csharp\npublic class MyService : IMyService\n{\n\tpublic Task DoSomething(MyServiceRequest request)\n\t{\n\t\treturn Task.FromResult(new MyServiceResult()\n\t\t{\n\t\t\tNewText = request.Text + \" from server\",\n\t\t\tNewValue = request.Value + 1\n\t\t});\n\t}\n}\n```\n\nPublish the service in `Startup.cs`:\n\n```csharp\napp.UseEndpoints(endpoints =\u003e\n{\n\tendpoints.MapGrpcService\u003cMyService\u003e();\n\t// ...\n}\n```\n\n## 4. Blazor.Client (Blazor Web Assembly) - consume the service\nAdd NuGet packages:\n* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client)\n* [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web) (prerelease)\n* [protobuf-net.Grpc](https://www.nuget.org/packages/protobuf-net.Grpc)\n\n### 4A. Direct consumption of the service\nConsume the service in your razor file:\n\n```csharp\nvar handler = new Grpc.Net.Client.Web.GrpcWebHandler(Grpc.Net.Client.Web.GrpcWebMode.GrpcWeb, new HttpClientHandler());\nusing (var channel = Grpc.Net.Client.GrpcChannel.ForAddress(\"https://localhost:44383/\", new Grpc.Net.Client.GrpcChannelOptions() { HttpClient = new HttpClient(handler) }))\n{\n\tvar testFacade = channel.CreateGrpcService\u003cIMyService\u003e();\n\tthis.result = await testFacade.DoSomething(request);\n}\n```\n\n### 4B. Consumption via dependency injection\nRegister a GrpcChannel in your `Program.cs` (or `Startup.cs:ConfigureServices()`)\n```csharp\nbuilder.Services.AddSingleton(services =\u003e\n{\n\t// Get the service address from appsettings.json\n\tvar config = services.GetRequiredService\u003cIConfiguration\u003e();\n\tvar backendUrl = config[\"BackendUrl\"];\n\n\t// If no address is set then fallback to the current webpage URL\n\tif (string.IsNullOrEmpty(backendUrl))\n\t{\n\t\tvar navigationManager = services.GetRequiredService\u003cNavigationManager\u003e();\n\t\tbackendUrl = navigationManager.BaseUri;\n\t}\n\n\t// Create a channel with a GrpcWebHandler that is addressed to the backend server.\n\t//\n\t// GrpcWebText is used because server streaming requires it. If server streaming is not used in your app\n\t// then GrpcWeb is recommended because it produces smaller messages.\n\tvar httpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler());\n\n\treturn GrpcChannel.ForAddress(\n\t\tbackendUrl,\n\t\tnew GrpcChannelOptions\n\t\t{\n\t\t\tHttpHandler = httpHandler,\n\t\t\t//CompressionProviders = ...,\n\t\t\t//Credentials = ...,\n\t\t\t//DisposeHttpClient = ...,\n\t\t\t//HttpClient = ...,\n\t\t\t//LoggerFactory = ...,\n\t\t\t//MaxReceiveMessageSize = ...,\n\t\t\t//MaxSendMessageSize = ...,\n\t\t\t//ThrowOperationCanceledOnCancellation = ...,\n\t\t});\n});\n```\n\nRegister the individual services (you might want to extract the \"logic\" to an extension method for better readability).\n```csharp\nbuilder.Services.AddTransient\u003cIMyService\u003e(services =\u003e\n{\n\tvar grpcChannel = services.GetRequiredService\u003cGrpcChannel\u003e();\n\treturn grpcChannel.CreateGrpcService\u003cIMyService\u003e();\n});\n```\n\nAnd now you can consume the services whereever needed (e.g. from .razor file):\n```csharp\n@inject\tIMyService MyService\n@code\n{\n\tasync Task Submit()\n\t{\n\t\tthis.result = await MyService.DoSomething(request);\n\t}\n}\n```\n\n# Advanced scenarios\nFor more advanced usage with error-handling, authentication + authorization and more, see our Havit.Blazor project template:\n* https://github.com/havit/NewProjectTemplate-Blazor\n\n# References, Credits\n* [Steve Sanderson: Using gRPC-Web with Blazor WebAssembly](https://blog.stevensanderson.com/2020/01/15/2020-01-15-grpc-web-in-blazor-webassembly/)\n* [Use gRPC in browser apps | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/grpc/browser)\n* [protobuf-net.Grpc - Getting Started](https://protobuf-net.github.io/protobuf-net.Grpc/gettingstarted)\n* https://github.com/grpc/grpc-dotnet/blob/master/examples/Blazor/Client/Program.cs\n* credits to @dani-herrera-udg for upgrading to .NET 6\n\n# Known Issues\n* https://github.com/dotnet/runtime/issues/62054 - may be hitting GC bug in .NET6","funding_links":[],"categories":["Sample Projects"],"sub_categories":["Others"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhakenr%2FBlazorGrpcWebCodeFirst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhakenr%2FBlazorGrpcWebCodeFirst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhakenr%2FBlazorGrpcWebCodeFirst/lists"}