![]() |
VOOZH | about |
dotnet add package Grpc.StatusProto --version 2.80.0
NuGet\Install-Package Grpc.StatusProto -Version 2.80.0
<PackageReference Include="Grpc.StatusProto" Version="2.80.0" />
<PackageVersion Include="Grpc.StatusProto" Version="2.80.0" />Directory.Packages.props
<PackageReference Include="Grpc.StatusProto" />Project file
paket add Grpc.StatusProto --version 2.80.0
#r "nuget: Grpc.StatusProto, 2.80.0"
#:package Grpc.StatusProto@2.80.0
#addin nuget:?package=Grpc.StatusProto&version=2.80.0Install as a Cake Addin
#tool nuget:?package=Grpc.StatusProto&version=2.80.0Install as a Cake Tool
This is a protoype NuGet package providing C# and .NET client and server side support for the gRPC richer error model.
This feature is already available in many other implementations including C++, Go, Java and Python.
This package has dependencies on these NuGet packages:
Google.Api.CommonProtos - to provide the proto implementations used by the richer error modelGrpc.Core.Api - for API classes such as RpcExceptionThe standard way for gRPC to report the success or failure of a gRPC call is for a
status code to be returned. If a call completes successfully the server returns an OK
status to the client, otherwise an error status code is returned with an optional string
error message that provides further details about what happened. This is known as the
standard error model and is the official gRPC error model supported by all gRPC
implementations.
There is another error model known as the richer error model that allows additional error details to be included by the server. These are expressed in protocol buffers messages, and a set of standard error message types is defined to cover most needs. The protobuf binary encoding of this extra error information is provided as trailing metadata in the response.
For more information on the richer error model see the gRPC documentation on error handling, and the Google APIs overview of the error model.
The error model is defined by the protocol buffers files status.proto
and error_details.proto,
and the Google.Api.CommonProtos NuGet package that provides the generated .NET classes
from these proto files.
The error is encapsulated by an instance of Google.Rpc.Status and
returned in the trailing response metadata with well-known key grpc-status-details-bin.
Setting and reading this metadata is handled
for you when using the methods provided in this package.
The server side uses C#'s Object and Collection initializer syntax.
The server returns the additional error information by throwing an RpcException that is
created from a Google.Rpc.Status which contains the details of the error.
To add messages to the Details repeated field in Google.Rpc.Status, wrap each one in Any.Pack() - see example below.
The Google.Rpc.Status extension method ToRpcException creates the appropriate RpcException from the status.
Example - creating and throwing a RpcException:
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
ArgumentNotNullOrEmpty(request.Name);
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
private static void ArgumentNotNullOrEmpty(string value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (string.IsNullOrEmpty(value))
{
throw 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"
}
}
})
}
}.ToRpcException();
}
}
Both Grpc.Core.StatusCode and Google.Rpc.Code define enums for a common
set of status codes such as NotFound, PermissionDenied, etc. They have the same values and are based on the codes defined
in grpc/status.h.
The recommendation is to use the values in Google.Rpc.Code as a convention.
This is a must for Google APIs and strongly recommended for third party services.
But users can use a different domain of values if they want to and as long as their
services are mutually compatible, things will work fine.
In the richer error model the RpcException will contain both a Grpc.Core.Status (for the
standard error model) and a Google.Rpc.Status (for the richer error model), each with their
own status code. While an application is free to set these to different values we recommend
that they are set to the same value to avoid ambiguity.
The richer error model defines a standard way of passing stack traces from the server to the
client. The DebugInfo message can be populated with stack traces and then it can
be included in the Details of the Google.Rpc.Status.
This package includes the extension method ToRpcDebugInfo for System.Exception to help
create the DebugInfo message with the details from the exception.
Example:
try
{
// ...
}
catch (Exception e)
{
throw new Google.Rpc.Status
{
Code = (int)Google.Rpc.Code.Internal,
Message = "Internal error",
Details =
{
// populate debugInfo from the exception
Any.Pack(e.ToRpcDebugInfo()),
// Add any other messages to the details ...
}
}.ToRpcException();
}
There is an extension method to retrieve a Google.Rpc.Status from the metadata in
an RpcException.
Once the Google.Rpc.Status has been retrieved the messages in the Details
can be unpacked. There are two ways of doing this:
GetDetail<T>() with one of the expected message typesDetails using UnpackDetailMessage()Example - calling GetDetail<T>():
void PrintError(RpcException ex)
{
// Get the status from the RpcException
Google.Rpc.Status? rpcStatus = ex.GetRpcStatus(); // Extension method
if (rpcStatus != null)
{
Console.WriteLine($"Google.Rpc Status: Code: {rpcStatus.Code}, Message: {rpcStatus.Message}");
// Try and get the ErrorInfo from the details
ErrorInfo? errorInfo = rpcStatus.GetDetail<ErrorInfo>();
if (errorInfo != null)
{
Console.WriteLine($"\tErrorInfo: Reason: {errorInfo.Reason}, Domain: {errorInfo.Domain}");
foreach (var md in errorInfo.Metadata)
{
Console.WriteLine($"\tKey: {md.Key}, Value: {md.Value}");
}
}
// etc, for any other messages expected in the Details ...
}
}
Example - iterating over all the messages in the Details:
void PrintStatusDetails(RpcException ex)
{
// Get the status from the RpcException
Google.Rpc.Status? rpcStatus = ex.GetRpcStatus(); // Extension method
if (rpcStatus != null)
{
// Decode each message item in the details in turn
foreach (var msg in rpcStatus.UnpackDetailMessages())
{
switch (msg)
{
case ErrorInfo errorInfo:
Console.WriteLine($"ErrorInfo: Reason: {errorInfo.Reason}, Domain: {errorInfo.Domain}");
foreach (var md in errorInfo.Metadata)
{
Console.WriteLine($"\tKey: {md.Key}, Value: {md.Value}");
}
break;
case BadRequest badRequest:
Console.WriteLine("BadRequest:");
foreach (BadRequest.Types.FieldViolation fv in badRequest.FieldViolations)
{
Console.WriteLine($"\tField: {fv.Field}, Description: {fv.Description}");
}
break;
// Other cases handled here ...
}
}
}
The model described above allows you to return an error status when the gRPC call finishes.
As an extension to the richer error model you may want to allow servers to send back multiple statuses when streaming responses without terminating the call.
One way of doing this is to include a google.rpc.Status message in the definition
of the response messages returned by the server. The client should also be aware
that it may receive a status in the response.
For example:
service WidgetLookupProvider {
rpc streamingLookup(stream WidgetReq) returns (stream WidgetRsp) {}
}
message WidgetReq {
string widget_name = 1;
}
message WidgetRsp {
oneof message{
// details when ok
string widget_details = 1;
// or error details
google.rpc.Status status = 2;
}
}
Note: the status.proto
and error_details.proto
files are provided in the Google.Api.CommonProtos NuGet package.
Example server code fragment:
await foreach (var request in requestStream.ReadAllAsync())
{
var response = new WidgetRsp();
// ... process the request ...
// to return an error
if (error)
{
response.Status = new Google.Rpc.Status { /* ... */ };
}
else
{
response.WidgetDetails = "the details";
}
}
Example client code fragment:
// reading the responses
var responseReaderTask = Task.Run(async () =>
{
await foreach (var rsp in call.ResponseStream.ReadAllAsync())
{
switch (rsp.MessageCase)
{
case WidgetRsp.MessageOneofCase.WidgetDetails:
// ... processes the details ...
break;
case WidgetRsp.MessageOneofCase.Status:
// ... handle the error ...
break;
}
}
});
// sending the requests
foreach (var request in requests)
{
await call.RequestStream.WriteAsync(request);
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 is compatible. |
| .NET Framework | net461 net461 was computed. net462 net462 is compatible. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on Grpc.StatusProto:
| Package | Downloads |
|---|---|
|
KurrentDB.Client
The base GRPC client library for the Kurrent Platform. Get the open source or commercial versions of KurrentDB from https://kurrent.io/ |
|
|
Device.GrpcClient
Package Description |
|
|
WolverineFx.Grpc
Code-first and proto-first gRPC service support for Wolverine, including gRPC message transport |
|
|
Device.GrpcCommon
Package Description |
|
|
FluxConfig.Provider
Microsoft.Extensions.Configuration provider for interacting with FluxConfig system. Provides automated retrieval and updating of the application's running configuration without the need to restart the application or interact with the deployment environment |
Showing the top 3 popular GitHub repositories that depend on Grpc.StatusProto:
| Repository | Stars |
|---|---|
|
kurrent-io/KurrentDB
KurrentDB is a database that's engineered for modern software applications and event-driven architectures. Its event-native design simplifies data modeling and preserves data integrity while the integrated streaming engine solves distributed messaging challenges and ensures data consistency.
|
|
|
JasperFx/wolverine
Supercharged .NET server side development!
|
|
|
kurrent-io/KurrentDB-Client-Dotnet
KurrentDB .NET Client
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.80.0 | 40,861 | 4/30/2026 |
| 2.80.0-pre1 | 134 | 4/1/2026 |
| 2.76.0 | 285,408 | 12/19/2025 |
| 2.76.0-pre1 | 366 | 11/13/2025 |
| 2.71.0 | 590,442 | 4/25/2025 |
| 2.71.0-pre1 | 297 | 4/16/2025 |
| 2.70.0 | 175,664 | 3/10/2025 |
| 2.70.0-pre1 | 238 | 2/26/2025 |
| 2.67.0 | 447,326 | 11/21/2024 |
| 2.67.0-pre1 | 212 | 10/22/2024 |
| 2.66.0 | 152,800 | 9/20/2024 |
| 2.66.0-pre1 | 205 | 9/6/2024 |
| 2.65.0 | 70,618 | 7/27/2024 |
| 2.65.0-pre1 | 222 | 7/20/2024 |
| 2.64.0 | 9,255 | 7/19/2024 |
| 2.64.0-pre1 | 9,739 | 7/15/2024 |
| 2.63.0 | 172,061 | 5/24/2024 |
| 2.63.0-pre1 | 253 | 5/8/2024 |
| 2.62.0 | 220,636 | 3/29/2024 |
| 2.62.0-pre1 | 302 | 3/8/2024 |