From abaaf4415c2bf1c1c97a8cba4e3c114e221489d3 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 9 Jan 2024 07:59:02 +0800 Subject: [PATCH] Add ProtoStatus example (#2273) --- examples/Error/Client/Client.csproj | 20 ++++++ examples/Error/Client/Program.cs | 56 ++++++++++++++++ examples/Error/Error.sln | 61 +++++++++++++++++ examples/Error/Proto/greet.proto | 33 ++++++++++ examples/Error/Server/GrpcValidation.cs | 54 +++++++++++++++ examples/Error/Server/Program.cs | 27 ++++++++ .../Server/Properties/launchSettings.json | 12 ++++ examples/Error/Server/Server.csproj | 20 ++++++ .../Error/Server/Services/GreeterService.cs | 32 +++++++++ .../Error/Server/appsettings.Development.json | 10 +++ examples/Error/Server/appsettings.json | 13 ++++ examples/README.md | 66 +++++++++++-------- 12 files changed, 376 insertions(+), 28 deletions(-) create mode 100644 examples/Error/Client/Client.csproj create mode 100644 examples/Error/Client/Program.cs create mode 100644 examples/Error/Error.sln create mode 100644 examples/Error/Proto/greet.proto create mode 100644 examples/Error/Server/GrpcValidation.cs create mode 100644 examples/Error/Server/Program.cs create mode 100644 examples/Error/Server/Properties/launchSettings.json create mode 100644 examples/Error/Server/Server.csproj create mode 100644 examples/Error/Server/Services/GreeterService.cs create mode 100644 examples/Error/Server/appsettings.Development.json create mode 100644 examples/Error/Server/appsettings.json diff --git a/examples/Error/Client/Client.csproj b/examples/Error/Client/Client.csproj new file mode 100644 index 000000000..7ff15b352 --- /dev/null +++ b/examples/Error/Client/Client.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0 + + + + + + + + + + + + + + + diff --git a/examples/Error/Client/Program.cs b/examples/Error/Client/Program.cs new file mode 100644 index 000000000..e5fe5bd82 --- /dev/null +++ b/examples/Error/Client/Program.cs @@ -0,0 +1,56 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Google.Rpc; +using Greet; +using Grpc.Core; +using Grpc.Net.Client; + +using var channel = GrpcChannel.ForAddress("https://localhost:5001"); +var client = new Greeter.GreeterClient(channel); + +Console.WriteLine("Hello world app"); +Console.WriteLine("==============="); + +while (true) +{ + Console.WriteLine(); + + Console.Write("Enter name: "); + var name = Console.ReadLine(); + + try + { + var reply = await client.SayHelloAsync(new HelloRequest { Name = name }); + Console.WriteLine("Greeting: " + reply.Message); + } + catch (RpcException ex) + { + Console.WriteLine($"Server error: {ex.Status.Detail}"); + + var badRequest = ex.GetRpcStatus()?.GetDetail(); + if (badRequest != null) + { + foreach (var fieldViolation in badRequest.FieldViolations) + { + Console.WriteLine($"Field: {fieldViolation.Field}"); + Console.WriteLine($"Description: {fieldViolation.Description}"); + } + } + } +} diff --git a/examples/Error/Error.sln b/examples/Error/Error.sln new file mode 100644 index 000000000..c15fc0471 --- /dev/null +++ b/examples/Error/Error.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34004.107 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.StatusProto", "..\..\src\Grpc.StatusProto\Grpc.StatusProto.csproj", "{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Api", "..\..\src\Grpc.Core.Api\Grpc.Core.Api.csproj", "{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client", "..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj", "{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Common", "..\..\src\Grpc.Net.Common\Grpc.Net.Common.csproj", "{23678E37-37D4-4543-9961-403B3760862B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server", "..\..\src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj", "{A1368174-6D27-49F1-B6DC-F1868CAE000F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU + {48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU + {08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Release|Any CPU.Build.0 = Release|Any CPU + {E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Release|Any CPU.Build.0 = Release|Any CPU + {E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Release|Any CPU.Build.0 = Release|Any CPU + {23678E37-37D4-4543-9961-403B3760862B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23678E37-37D4-4543-9961-403B3760862B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23678E37-37D4-4543-9961-403B3760862B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23678E37-37D4-4543-9961-403B3760862B}.Release|Any CPU.Build.0 = Release|Any CPU + {A1368174-6D27-49F1-B6DC-F1868CAE000F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1368174-6D27-49F1-B6DC-F1868CAE000F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1368174-6D27-49F1-B6DC-F1868CAE000F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1368174-6D27-49F1-B6DC-F1868CAE000F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD} + EndGlobalSection +EndGlobal diff --git a/examples/Error/Proto/greet.proto b/examples/Error/Proto/greet.proto new file mode 100644 index 000000000..26d0c794d --- /dev/null +++ b/examples/Error/Proto/greet.proto @@ -0,0 +1,33 @@ +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package greet; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/Error/Server/GrpcValidation.cs b/examples/Error/Server/GrpcValidation.cs new file mode 100644 index 000000000..b9ed5d48e --- /dev/null +++ b/examples/Error/Server/GrpcValidation.cs @@ -0,0 +1,54 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Runtime.CompilerServices; +using Google.Protobuf.WellKnownTypes; +using Google.Rpc; +using Grpc.Core; + +namespace Server; + +public static class GrpcValidation +{ + public static void ArgumentNotNullOrEmpty(string value, [CallerArgumentExpression(nameof(value))] string? paramName = null) + { + if (string.IsNullOrEmpty(value)) + { + var status = new Google.Rpc.Status + { + Code = (int)Code.InvalidArgument, + Message = "Bad request", + Details = + { + Any.Pack(new BadRequest + { + FieldViolations = + { + new BadRequest.Types.FieldViolation + { + Field = paramName, + Description = "Value is null or empty" + } + } + }) + } + }; + throw status.ToRpcException(); + } + } +} diff --git a/examples/Error/Server/Program.cs b/examples/Error/Server/Program.cs new file mode 100644 index 000000000..74aeee754 --- /dev/null +++ b/examples/Error/Server/Program.cs @@ -0,0 +1,27 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Server; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddGrpc(); + +var app = builder.Build(); +app.MapGrpcService(); + +app.Run(); diff --git a/examples/Error/Server/Properties/launchSettings.json b/examples/Error/Server/Properties/launchSettings.json new file mode 100644 index 000000000..fae4961d9 --- /dev/null +++ b/examples/Error/Server/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Server": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "https://localhost:5001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/examples/Error/Server/Server.csproj b/examples/Error/Server/Server.csproj new file mode 100644 index 000000000..d7abe248b --- /dev/null +++ b/examples/Error/Server/Server.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + + + + + + + + + + + + + + + + diff --git a/examples/Error/Server/Services/GreeterService.cs b/examples/Error/Server/Services/GreeterService.cs new file mode 100644 index 000000000..540ebfcbd --- /dev/null +++ b/examples/Error/Server/Services/GreeterService.cs @@ -0,0 +1,32 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Greet; +using Grpc.Core; + +namespace Server; + +public class GreeterService : Greeter.GreeterBase +{ + public override Task SayHello(HelloRequest request, ServerCallContext context) + { + GrpcValidation.ArgumentNotNullOrEmpty(request.Name); + + return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); + } +} diff --git a/examples/Error/Server/appsettings.Development.json b/examples/Error/Server/appsettings.Development.json new file mode 100644 index 000000000..fe20c40cc --- /dev/null +++ b/examples/Error/Server/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" + } + } +} diff --git a/examples/Error/Server/appsettings.json b/examples/Error/Server/appsettings.json new file mode 100644 index 000000000..f5f63744b --- /dev/null +++ b/examples/Error/Server/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } +} diff --git a/examples/README.md b/examples/README.md index b8c25e053..14a93010b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -8,7 +8,7 @@ If you are brand new to gRPC on .NET a good place to start is the getting starte ## [Greeter](./Greeter) -The greeter shows how to create unary (non-streaming) gRPC methods in ASP.NET Core, and call them from a client. +The greeter example shows how to create unary (non-streaming) gRPC methods in ASP.NET Core, and call them from a client. ##### Scenarios: @@ -16,7 +16,7 @@ The greeter shows how to create unary (non-streaming) gRPC methods in ASP.NET Co ## [Counter](./Counter) -The counter shows how to create unary (non-streaming), client streaming and server streaming gRPC methods in ASP.NET Core, and call them from a client. +The counter example shows how to create unary (non-streaming), client streaming and server streaming gRPC methods in ASP.NET Core, and call them from a client. ##### Scenarios: @@ -26,7 +26,7 @@ The counter shows how to create unary (non-streaming), client streaming and serv ## [Mailer](./Mailer) -The mailer shows how to create a bi-directional streaming gRPC method in ASP.NET Core and call it from a client. The server reacts to messages sent from the client. +The mailer example shows how to create a bi-directional streaming gRPC method in ASP.NET Core and call it from a client. The server reacts to messages sent from the client. ##### Scenarios: @@ -34,7 +34,7 @@ The mailer shows how to create a bi-directional streaming gRPC method in ASP.NET ## [Interceptor](./Interceptor) -The interceptor shows how to use gRPC interceptors on the client and server. The client interceptor adds additional metadata to each call and the server interceptor logs that metadata on the server. +The interceptor example shows how to use gRPC interceptors on the client and server. The client interceptor adds additional metadata to each call and the server interceptor logs that metadata on the server. ##### Scenarios: @@ -45,7 +45,7 @@ The interceptor shows how to use gRPC interceptors on the client and server. The ## [Racer](./Racer) -The racer shows how to create a bi-directional streaming gRPC method in ASP.NET Core and call it from a client. The client and the server each send messages as quickly as possible. +The racer example shows how to create a bi-directional streaming gRPC method in ASP.NET Core and call it from a client. The client and the server each send messages as quickly as possible. ##### Scenarios: @@ -53,7 +53,7 @@ The racer shows how to create a bi-directional streaming gRPC method in ASP.NET ## [Ticketer](./Ticketer) -The ticketer shows how to use gRPC with [authentication and authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security). This example has a gRPC method marked with an `[Authorize]` attribute. The client can only call the method if it has been authenticated by the server and passes a valid JWT token with the gRPC call. +The ticketer example shows how to use gRPC with [authentication and authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security). This example has a gRPC method marked with an `[Authorize]` attribute. The client can only call the method if it has been authenticated by the server and passes a valid JWT token with the gRPC call. ##### Scenarios: @@ -63,7 +63,7 @@ The ticketer shows how to use gRPC with [authentication and authorization in ASP ## [Reflector](./Reflector) -The reflector shows how to host the [gRPC Server Reflection Protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) service and call its methods from a client. +The reflector example shows how to host the [gRPC Server Reflection Protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) service and call its methods from a client. ##### Scenarios: @@ -72,7 +72,7 @@ The reflector shows how to host the [gRPC Server Reflection Protocol](https://gi ## [Certifier](./Certifier) -The certifier shows how to configure the client and the server to use a [TLS client certificate](https://blogs.msdn.microsoft.com/kaushal/2015/05/27/client-certificate-authentication-part-1/) with a gRPC call. The server is configured to require a client certificate using [ASP.NET Core client certificate authentication](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth). +The certifier example shows how to configure the client and the server to use a [TLS client certificate](https://blogs.msdn.microsoft.com/kaushal/2015/05/27/client-certificate-authentication-part-1/) with a gRPC call. The server is configured to require a client certificate using [ASP.NET Core client certificate authentication](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth). > **NOTE:** client.pfx is a self-signed certificate. When running the client you may get an error that the certificate is not trusted: `The certificate chain was issued by an authority that is not trusted`. [Add the certificate](https://www.thesslstore.com/knowledgebase/ssl-install/how-to-import-intermediate-root-certificates-using-mmc/) to your computer's trusted root cert store to fix this error. Don't use this certificate in production environments. @@ -85,7 +85,7 @@ The certifier shows how to configure the client and the server to use a [TLS cli ## [Worker](./Worker) -The worker shows how to use call a gRPC server with a [.NET worker service](https://docs.microsoft.com/aspnet/core/fundamentals/host/hosted-services). The client uses the worker service to make a gRPC call on a timed internal. The gRPC client factory is used to create a client, which is injected into the service using dependency injection. +The worker example shows how to use call a gRPC server with a [.NET worker service](https://docs.microsoft.com/aspnet/core/fundamentals/host/hosted-services). The client uses the worker service to make a gRPC call on a timed internal. The gRPC client factory is used to create a client, which is injected into the service using dependency injection. The server is configured as a normal .NET web app, which uses the same [generic host](https://docs.microsoft.com/aspnet/core/fundamentals/host/generic-host) as a worker service to host its web server. @@ -101,7 +101,7 @@ The client or server can be run as a [Windows service](https://en.wikipedia.org/ ## [Aggregator](./Aggregator) -The aggregator shows how a to make nested gRPC calls (a gRPC service calling another gRPC service). The gRPC client factory is used in ASP.NET Core to inject a client into services. The gRPC client factory is configured to propagate the context from the original call to the nested call. In this example the cancellation from the client will automatically propagate through to nested gRPC calls. +The aggregator example shows how a to make nested gRPC calls (a gRPC service calling another gRPC service). The gRPC client factory is used in ASP.NET Core to inject a client into services. The gRPC client factory is configured to propagate the context from the original call to the nested call. In this example the cancellation from the client will automatically propagate through to nested gRPC calls. The aggregator can optionally be run with [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet) enabled. OpenTelemetry is configured to capture tracing information and send it to [Zipkin](https://zipkin.io), a distributed tracing system. A Zipkin server needs to be running to receive traces. The simplest way to do that is [run the Zipkin Docker image](https://zipkin.io/pages/quickstart.html). @@ -120,7 +120,7 @@ dotnet run --EnableOpenTelemetry=true ## [Tester](./Tester) -The tester shows how to test gRPC services. The unit tests create and test a gRPC service directly. The functional tests show how to use [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) (version 3.1.2 or greater required) to host a gRPC service with an in-memory test server and call it using a gRPC client. The functional tests write client and server logs to the test output. +The tester example shows how to test gRPC services. The unit tests create and test a gRPC service directly. The functional tests show how to use [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) (version 3.1.2 or greater required) to host a gRPC service with an in-memory test server and call it using a gRPC client. The functional tests write client and server logs to the test output. The tests also show how to mock a gRPC client when testing gRPC client apps. @@ -132,7 +132,7 @@ The tests also show how to mock a gRPC client when testing gRPC client apps. ## [Progressor](./Progressor) -The progressor shows how to use server streaming to notify the caller about progress on the server. +The progressor example shows how to use server streaming to notify the caller about progress on the server. ##### Scenarios: @@ -141,7 +141,7 @@ The progressor shows how to use server streaming to notify the caller about prog ## [Vigor](./Vigor) -The vigor example shows how to integrate [ASP.NET Core health checks](https://docs.microsoft.com/aspnet/core/host-and-deploy/health-checks) with the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) service, and call its methods from a client. +The vigor example example shows how to integrate [ASP.NET Core health checks](https://docs.microsoft.com/aspnet/core/host-and-deploy/health-checks) with the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) service, and call its methods from a client. ##### Scenarios: @@ -151,7 +151,7 @@ The vigor example shows how to integrate [ASP.NET Core health checks](https://do ## [Compressor](./Compressor) -The compressor example shows how to enable compression of gRPC request and response messages using gzip. +The compressor example example shows how to enable compression of gRPC request and response messages using gzip. > **IMPORTANT:** Using compression with dynamically generated content can lead to security problems such as the [CRIME](https://wikipedia.org/wiki/CRIME_(security_exploit)) and [BREACH](https://wikipedia.org/wiki/BREACH_(security_exploit)) attacks. @@ -162,7 +162,7 @@ The compressor example shows how to enable compression of gRPC request and respo ## [Liber](./Liber) -The liber example shows how to add Protobuf messages to a shared .NET project. Sharing generated messages is an alternative to each project generating their own copy. Protobuf messages in a shared project makes it easier to write reusable libraries that use messages. +The liber example example shows how to add Protobuf messages to a shared .NET project. Sharing generated messages is an alternative to each project generating their own copy. Protobuf messages in a shared project makes it easier to write reusable libraries that use messages. This example has two proto files: @@ -182,7 +182,7 @@ The `Name` .NET type is generated from *common.proto* in the common project and ## [Browser](./Browser) -The browser example shows how to use [gRPC-Web](https://github.com/grpc/grpc-web) with ASP.NET Core to call a gRPC service from a browser. Browser apps have limited HTTP/2 features and need to use gRPC-Web instead. This example requires [npm and NodeJS](https://nodejs.org/) to be installed on your computer. +The browser example example shows how to use [gRPC-Web](https://github.com/grpc/grpc-web) with ASP.NET Core to call a gRPC service from a browser. Browser apps have limited HTTP/2 features and need to use gRPC-Web instead. This example requires [npm and NodeJS](https://nodejs.org/) to be installed on your computer. The gRPC-Web JavaScript client was generated from *greet.proto* using [`protoc`](https://github.com/protocolbuffers/protobuf/releases) with the [`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases) plugin. @@ -193,7 +193,7 @@ The gRPC-Web JavaScript client was generated from *greet.proto* using [`protoc`] ## [Blazor](./Blazor) -The blazor example shows how to call a gRPC service from a Blazor WebAssembly app. Because Blazor WebAssembly is hosted in the browser it has limited HTTP/2 features and needs to use gRPC-Web instead. +The blazor example example shows how to call a gRPC service from a Blazor WebAssembly app. Because Blazor WebAssembly is hosted in the browser it has limited HTTP/2 features and needs to use gRPC-Web instead. ##### Scenarios: @@ -204,7 +204,7 @@ The blazor example shows how to call a gRPC service from a Blazor WebAssembly ap ## [Spar](./Spar) -The spar example shows how to call a gRPC service from a single page application (SPA) and make cross-origin gRPC-Web requests. The SPA uses [Vue.js](https://vuejs.org/) and [gRPC-Web](https://github.com/grpc/grpc-web). The server is configured to support [Cross Origin Resource Sharing (CORS)](https://docs.microsoft.com/aspnet/core/security/cors). This example requires [npm and NodeJS](https://nodejs.org/) to be installed on your computer. +The spar example example shows how to call a gRPC service from a single page application (SPA) and make cross-origin gRPC-Web requests. The SPA uses [Vue.js](https://vuejs.org/) and [gRPC-Web](https://github.com/grpc/grpc-web). The server is configured to support [Cross Origin Resource Sharing (CORS)](https://docs.microsoft.com/aspnet/core/security/cors). This example requires [npm and NodeJS](https://nodejs.org/) to be installed on your computer. The gRPC-Web JavaScript client was generated from *greet.proto* using [`protoc`](https://github.com/protocolbuffers/protobuf/releases) with the [`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases) plugin. @@ -216,7 +216,7 @@ The gRPC-Web JavaScript client was generated from *greet.proto* using [`protoc`] ## [Transcoder](./Transcoder) -The transcoder shows how to use [gRPC JSON transcoding](https://docs.microsoft.com/aspnet/core/grpc/httpapi) to generate RESTful APIs from gRPC services. +The transcoder example shows how to use [gRPC JSON transcoding](https://docs.microsoft.com/aspnet/core/grpc/httpapi) to generate RESTful APIs from gRPC services. ##### Scenarios: @@ -228,7 +228,7 @@ The transcoder shows how to use [gRPC JSON transcoding](https://docs.microsoft.c * .NET 5 or later * Linux, MacOS or a [modern version of Windows](https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/) -The transporter example shows how to use gRPC over non-TCP transports. This example uses a [Unix domain socket (UDS)](https://en.wikipedia.org/wiki/Unix_domain_socket) to send gRPC messages between the client and server. +The transporter example example shows how to use gRPC over non-TCP transports. This example uses a [Unix domain socket (UDS)](https://en.wikipedia.org/wiki/Unix_domain_socket) to send gRPC messages between the client and server. To use gRPC with UDS: @@ -243,7 +243,7 @@ To use gRPC with UDS: ## [Coder](./Coder) -The coder example shows how to create a code-first gRPC service and client. This example uses [protobuf-net.Grpc](https://github.com/protobuf-net/protobuf-net.Grpc), a community project that adds code-first support to `Grpc.AspNetCore` and `Grpc.Net.Client`. +The coder example example shows how to create a code-first gRPC service and client. This example uses [protobuf-net.Grpc](https://github.com/protobuf-net/protobuf-net.Grpc), a community project that adds code-first support to `Grpc.AspNetCore` and `Grpc.Net.Client`. Code-first is a good choice if an app is written entirely in .NET. Code contracts can't be used by other languages and cross-platform apps should use *.proto* contracts. @@ -255,7 +255,7 @@ Code-first is a good choice if an app is written entirely in .NET. Code contract ## [Retrier](./Retrier) -The retrier example shows how to configure a client to use gRPC retries to retry failed calls. gRPC retries enables resilient, fault tolerant gRPC apps in .NET. +The retrier example example shows how to configure a client to use gRPC retries to retry failed calls. gRPC retries enables resilient, fault tolerant gRPC apps in .NET. ##### Scenarios: @@ -263,7 +263,7 @@ The retrier example shows how to configure a client to use gRPC retries to retry ## [Container](./Container) -The container example shows how to create a gRPC Kubernetes app. There are two containers in the example: a Blazor Server frontend, and a gRPC server backend with multiple replicas. The frontend uses gRPC client-side load balancing to call backend instances. +The container example example shows how to create a gRPC Kubernetes app. There are two containers in the example: a Blazor Server frontend, and a gRPC server backend with multiple replicas. The frontend uses gRPC client-side load balancing to call backend instances. ##### Scenarios: @@ -272,7 +272,7 @@ The container example shows how to create a gRPC Kubernetes app. There are two c ## [Uploader](./Uploader) -The uploader shows how to upload a file in chunks using a client streaming gRPC method. +The uploader example shows how to upload a file in chunks using a client streaming gRPC method. ##### Scenarios: @@ -281,7 +281,7 @@ The uploader shows how to upload a file in chunks using a client streaming gRPC ## [Downloader](./Downloader) -The downloader shows how to download a file in chunks using a server streaming gRPC method. +The downloader example shows how to download a file in chunks using a server streaming gRPC method. ##### Scenarios: @@ -290,7 +290,7 @@ The downloader shows how to download a file in chunks using a server streaming g ## [Locator](./Locator) -The locator shows how to add host constraints to gRPC services. This example adds two services: +The locator example shows how to add host constraints to gRPC services. This example adds two services: * Internal gRPC service is only accessible over port 5001. * External gRPC service is only accessible over port 5000. @@ -301,7 +301,7 @@ The locator shows how to add host constraints to gRPC services. This example add ## [Channeler](./Channeler) -The channeler shows how to use `System.Threading.Channels` to safely read and write gRPC messages from multiple background tasks. +The channeler example shows how to use `System.Threading.Channels` to safely read and write gRPC messages from multiple background tasks. ##### Scenarios: @@ -312,9 +312,19 @@ The channeler shows how to use `System.Threading.Channels` to safely read and wr ## [Frameworker](./Frameworker) -The frameworker shows how to call gRPC services from a .NET Framework client using `WinHttpHandler`. +The frameworker example shows how to call gRPC services from a .NET Framework client using `WinHttpHandler`. ##### Scenarios: * .NET Framework * [`WinHttpHandler`](https://docs.microsoft.com/dotnet/api/system.net.http.winhttphandler) + +## [Error](./Error) + +The error example shows how to use a richer error model with `Grpc.StatusProto`. This package includes helper methods for the server to return complex error information with [`google.rpc.Status`](https://cloud.google.com/apis/design/errors#error_model) from the server and read the error information in the client. + +##### Scenarios: + +* Error handling +* Validation +* [`google.rpc.Status`](https://cloud.google.com/apis/design/errors#error_model)