Skip to content

Commit

Permalink
Cherry pick grpc exception handling change to 0.11 (#431)
Browse files Browse the repository at this point in the history
* grpc exception handling sample (#427)

* rpc exception handling

* Upgrade grpc to 2.32.0 (#413)

* fix comment

Co-authored-by: Young Bu Park <[email protected]>
  • Loading branch information
vinayada1 and youngbupark authored Oct 14, 2020
1 parent ec015be commit 3b3800b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,17 @@ public async Task<ActionResult<Account>> Withdraw(Transaction transaction, [From
await state.SaveAsync();
return state.Value;
}

/// <summary>
/// Method for returning a BadRequest result which will cause Dapr sidecar to throw an RpcException
/// </summary>
[HttpPost("throwException")]
public async Task<ActionResult<Account>> 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" });
}
}
}
5 changes: 5 additions & 0 deletions samples/Client/DaprClient/DaprClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
<ProjectReference Include="..\..\..\src\Dapr.Client\Dapr.Client.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.13.0" />
<PackageReference Include="Google.Api.CommonProtos" Version="2.2.0" />
</ItemGroup>

</Project>
44 changes: 44 additions & 0 deletions samples/Client/DaprClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace DaprClient
using System.Threading.Tasks;
using Dapr.Client;
using Dapr.Client.Http;
using Grpc.Core;

/// <summary>
/// Shows Dapr client calls.
Expand All @@ -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";

/// <summary>
/// Main entry point.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<Google.Rpc.ErrorInfo>();
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; }
Expand Down
30 changes: 30 additions & 0 deletions samples/Client/DaprClient/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Google.Rpc.ErrorInfo>();
Console.WriteLine("Grpc Exception: Http Error Message: " + rpcError.Metadata[daprErrorInfoHTTPErrorMetadata]);
Console.WriteLine("Grpc Exception: Http Status Code: " + rpcError.Metadata[daprErrorInfoHTTPCodeMetadata]);
}
}
```
6 changes: 3 additions & 3 deletions src/Dapr.Client/Dapr.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<Description>This package contains the reference assemblies for developing services using Dapr.</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.11.4" />
<PackageReference Include="Grpc.Net.Client" Version="2.27.0" />
<PackageReference Include="Grpc.Tools" Version="2.27.0" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="3.13.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.32.0" />
<PackageReference Include="Grpc.Tools" Version="2.32.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Folder Include="Protos\" />
Expand Down
8 changes: 4 additions & 4 deletions test/Dapr.Client.Test/Dapr.Client.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.9.0" />
<PackageReference Include="Google.Protobuf" Version="3.11.4" />
<PackageReference Include="Grpc.Core.Testing" Version="2.31.0-pre1" />
<PackageReference Include="Grpc.Net.Client" Version="2.27.0" />
<PackageReference Include="Grpc.Tools" Version="2.27.0" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="3.13.0" />
<PackageReference Include="Grpc.Core.Testing" Version="2.32.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.32.0" />
<PackageReference Include="Grpc.Tools" Version="2.32.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
Expand Down

0 comments on commit 3b3800b

Please sign in to comment.