From e64825c302e1eacac43d2b21049fddaa25e11902 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch <jtattermusch@google.com> Date: Tue, 8 Aug 2017 16:10:23 +0200 Subject: [PATCH] Populate trailers in RpcException --- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 8 +++---- src/csharp/Grpc.Core/RpcException.cs | 28 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 6e6ca7cd53..17109de587 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -329,7 +329,7 @@ namespace Grpc.Core.Internal protected override Exception GetRpcExceptionClientOnly() { - return new RpcException(finishedStatus.Value.Status); + return new RpcException(finishedStatus.Value.Status, finishedStatus.Value.Trailers); } protected override Task CheckSendAllowedOrEarlyResult() @@ -348,7 +348,7 @@ namespace Grpc.Core.Internal // Writing after the call has finished is not a programming error because server can close // the call anytime, so don't throw directly, but let the write task finish with an error. var tcs = new TaskCompletionSource<object>(); - tcs.SetException(new RpcException(finishedStatus.Value.Status)); + tcs.SetException(new RpcException(finishedStatus.Value.Status, finishedStatus.Value.Trailers)); return tcs.Task; } @@ -468,7 +468,7 @@ namespace Grpc.Core.Internal var status = receivedStatus.Status; if (status.StatusCode != StatusCode.OK) { - unaryResponseTcs.SetException(new RpcException(status)); + unaryResponseTcs.SetException(new RpcException(status, receivedStatus.Trailers)); return; } @@ -506,7 +506,7 @@ namespace Grpc.Core.Internal var status = receivedStatus.Status; if (status.StatusCode != StatusCode.OK) { - streamingResponseCallFinishedTcs.SetException(new RpcException(status)); + streamingResponseCallFinishedTcs.SetException(new RpcException(status, receivedStatus.Trailers)); return; } diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs index 01b9e4fb1a..d2c912e73a 100644 --- a/src/csharp/Grpc.Core/RpcException.cs +++ b/src/csharp/Grpc.Core/RpcException.cs @@ -17,6 +17,7 @@ #endregion using System; +using Grpc.Core.Utils; namespace Grpc.Core { @@ -26,6 +27,7 @@ namespace Grpc.Core public class RpcException : Exception { private readonly Status status; + private readonly Metadata trailers; /// <summary> /// Creates a new <c>RpcException</c> associated with given status. @@ -34,6 +36,7 @@ namespace Grpc.Core public RpcException(Status status) : base(status.ToString()) { this.status = status; + this.trailers = Metadata.Empty; } /// <summary> @@ -44,6 +47,18 @@ namespace Grpc.Core public RpcException(Status status, string message) : base(message) { this.status = status; + this.trailers = Metadata.Empty; + } + + /// <summary> + /// Creates a new <c>RpcException</c> associated with given status and trailing response metadata. + /// </summary> + /// <param name="status">Resulting status of a call.</param> + /// <param name="trailers">Response trailing metadata.</param> + public RpcException(Status status, Metadata trailers) : base(status.ToString()) + { + this.status = status; + this.trailers = GrpcPreconditions.CheckNotNull(trailers); } /// <summary> @@ -56,5 +71,18 @@ namespace Grpc.Core return status; } } + + /// <summary> + /// Gets the call trailing metadata. + /// Trailers only have meaningful content for client-side calls (in which case they represent the trailing metadata sent by the server when closing the call). + /// Instances of <c>RpcException</c> thrown by the server-side part of the stack will have trailers always set to empty. + /// </summary> + public Metadata Trailers + { + get + { + return trailers; + } + } } } -- GitLab