diff --git a/samples/AspNetCore/ControllerSample/Controllers/SampleController.cs b/samples/AspNetCore/ControllerSample/Controllers/SampleController.cs index 38496cd72..6df151125 100644 --- a/samples/AspNetCore/ControllerSample/Controllers/SampleController.cs +++ b/samples/AspNetCore/ControllerSample/Controllers/SampleController.cs @@ -80,5 +80,17 @@ public async Task> Withdraw(Transaction transaction, [From await state.SaveAsync(); return state.Value; } + + /// + /// Method for returning a BadRequest result which will cause Dapr sidecar to throw an RpcException + /// + [HttpPost("throwException")] + public async Task> ThrowException(Transaction transaction, [FromServices] DaprClient daprClient) + { + Console.WriteLine("Enter ThrowException"); + var task = Task.Delay(10); + await task; + return BadRequest(new { statusCode = 400, message = "bad request" }); + } } } diff --git a/samples/Client/DaprClient/DaprClient.csproj b/samples/Client/DaprClient/DaprClient.csproj index 948eca75e..c446c69be 100644 --- a/samples/Client/DaprClient/DaprClient.csproj +++ b/samples/Client/DaprClient/DaprClient.csproj @@ -9,4 +9,9 @@ + + + + + diff --git a/samples/Client/DaprClient/Program.cs b/samples/Client/DaprClient/Program.cs index 7784baf1a..65ded2b71 100644 --- a/samples/Client/DaprClient/Program.cs +++ b/samples/Client/DaprClient/Program.cs @@ -11,6 +11,7 @@ namespace DaprClient using System.Threading.Tasks; using Dapr.Client; using Dapr.Client.Http; + using Grpc.Core; /// /// Shows Dapr client calls. @@ -20,6 +21,10 @@ public class Program private static readonly string stateKeyName = "mykey"; private static readonly string storeName = "statestore"; private static readonly string pubsubName = "pubsub"; + private static readonly string daprErrorInfoHTTPCodeMetadata = "http.code"; + private static readonly string daprErrorInfoHTTPErrorMetadata = "http.error_message"; + private static readonly string grpcStatusDetails = "grpc-status-details-bin"; + private static readonly string grpcErrorInfoDetail = "google.rpc.ErrorInfo"; /// /// Main entry point. @@ -55,6 +60,12 @@ public static async Task Main(string[] args) // Read State await GetStateAfterTransactionAsync(client); + if (args.Length > 0 && args[0] == "rpc-exception") + { + // Invoke /throwException route on the Controller sample server + await InvokeThrowExceptionOperationAsync(client); + } + #region Service Invoke - Required RoutingService //// This provides an example of how to invoke a method on another REST service that is listening on http. //// To use it run RoutingService in this solution. @@ -209,6 +220,39 @@ internal static async Task InvokeBalanceServiceOperationAsync(DaprClient client) Console.WriteLine($"Received balance {res.Balance}"); } + internal static async Task InvokeThrowExceptionOperationAsync(DaprClient client) + { + Console.WriteLine("Invoking ThrowException"); + var data = new { id = "17", amount = (decimal)10, }; + + HTTPExtension httpExtension = new HTTPExtension() + { + Verb = HTTPVerb.Post + }; + + try + { + // Invokes a POST method named "throwException" that takes input of type "Transaction" as defined in the ControllerSample. + await client.InvokeMethodAsync("controller", "throwException", data, httpExtension); + } + catch (RpcException ex) + { + var entry = ex.Trailers.Get(grpcStatusDetails); + var status = Google.Rpc.Status.Parser.ParseFrom(entry.ValueBytes); + Console.WriteLine("Grpc Exception Message: " + status.Message); + Console.WriteLine("Grpc Statuscode: " + status.Code); + foreach(var detail in status.Details) + { + if(Google.Protobuf.WellKnownTypes.Any.GetTypeName(detail.TypeUrl) == grpcErrorInfoDetail) + { + var rpcError = detail.Unpack(); + Console.WriteLine("Grpc Exception: Http Error Message: " + rpcError.Metadata[daprErrorInfoHTTPErrorMetadata]); + Console.WriteLine("Grpc Exception: Http Status Code: " + rpcError.Metadata[daprErrorInfoHTTPCodeMetadata]); + } + } + } + } + private class Widget { public string Size { get; set; } diff --git a/samples/Client/DaprClient/Readme.md b/samples/Client/DaprClient/Readme.md index 272ddf748..411b02ddf 100644 --- a/samples/Client/DaprClient/Readme.md +++ b/samples/Client/DaprClient/Readme.md @@ -115,3 +115,33 @@ The method *PublishDepositeEventToRoutingSampleAsync* demonstrates how to publis ```c# await client.PublishEventAsync("deposit", new { id = "17", amount = (decimal)10, }); ``` + + +## Handling RpcException + +Run the controller sample as follows from samples/AspNetCore/ControllerSample directory:- +``` +dapr run --app-id controller --app-port 5000 dotnet run +``` + +Run the client sample as follows from samples/Client/DaprClient directory. The "rpc-exception" argument invokes a route on the server side that causes it to throw an RpcException:- +``` +dapr run --app-id gRPC_Client dotnet run rpc-exception +``` + +The controller sample has a route "/throwException" that returns a BadRequest result which causes the Dapr sidecar to throw an RpcException. The method *InvokeThrowExceptionOperationAsync* on the client side demonstrates how to extract the error message from RpcException. +```c# + var entry = ex.Trailers.Get(grpcStatusDetails); + var status = Google.Rpc.Status.Parser.ParseFrom(entry.ValueBytes); + Console.WriteLine("Grpc Exception Message: " + status.Message); + Console.WriteLine("Grpc Statuscode: " + status.Code); + foreach(var detail in status.Details) + { + if(Google.Protobuf.WellKnownTypes.Any.GetTypeName(detail.TypeUrl) == grpcErrorInfoDetail) + { + var rpcError = detail.Unpack(); + Console.WriteLine("Grpc Exception: Http Error Message: " + rpcError.Metadata[daprErrorInfoHTTPErrorMetadata]); + Console.WriteLine("Grpc Exception: Http Status Code: " + rpcError.Metadata[daprErrorInfoHTTPCodeMetadata]); + } + } + ``` \ No newline at end of file diff --git a/src/Dapr.Client/Dapr.Client.csproj b/src/Dapr.Client/Dapr.Client.csproj index a0b3ad170..d5fafc628 100644 --- a/src/Dapr.Client/Dapr.Client.csproj +++ b/src/Dapr.Client/Dapr.Client.csproj @@ -14,9 +14,9 @@ This package contains the reference assemblies for developing services using Dapr. - - - + + + diff --git a/test/Dapr.Client.Test/Dapr.Client.Test.csproj b/test/Dapr.Client.Test/Dapr.Client.Test.csproj index 543f319cd..19fa4b6a0 100644 --- a/test/Dapr.Client.Test/Dapr.Client.Test.csproj +++ b/test/Dapr.Client.Test/Dapr.Client.Test.csproj @@ -5,10 +5,10 @@ - - - - + + + +