From 4d703268adb6769b835070d3222a39c7fa399303 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch <jtattermusch@google.com> Date: Mon, 23 Feb 2015 11:33:44 -0800 Subject: [PATCH] Fix exception unwrapping for unary call --- src/csharp/Grpc.Core/Calls.cs | 14 ----- src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + src/csharp/Grpc.Core/Internal/AsyncCall.cs | 14 +++-- src/csharp/Grpc.Core/RpcException.cs | 3 +- src/csharp/Grpc.Core/ServerCallHandler.cs | 2 + src/csharp/Grpc.Core/Utils/ExceptionHelper.cs | 57 +++++++++++++++++++ 6 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 src/csharp/Grpc.Core/Utils/ExceptionHelper.cs diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index c0973234e2..ee2208e5c2 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -49,20 +49,6 @@ namespace Grpc.Core { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer); return asyncCall.UnaryCall(call.Channel, call.MethodName, req); - - //TODO: implement this in real synchronous style. -// try { -// return AsyncUnaryCall(call, req, token).Result; -// } catch(AggregateException ae) { -// foreach (var e in ae.InnerExceptions) -// { -// if (e is RpcException) -// { -// throw e; -// } -// } -// throw; -// } } public static async Task<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 664d534dc2..135ce26cbd 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -63,6 +63,7 @@ <Compile Include="Internal\ServerStreamingOutputObserver.cs" /> <Compile Include="Internal\BatchContextSafeHandleNotOwned.cs" /> <Compile Include="Utils\BenchmarkUtil.cs" /> + <Compile Include="Utils\ExceptionHelper.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 7c40661cf4..dadc9ab76c 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -38,6 +38,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Utils; namespace Grpc.Core.Internal { @@ -130,10 +131,15 @@ namespace Grpc.Core.Internal } call.BlockingUnary(cq, payload, unaryResponseHandler); - // task should be finished once BlockingUnary returns. - return unaryResponseTcs.Task.Result; - - // TODO: unwrap aggregate exception... + try + { + // Once the blocking call returns, the result should be available synchronously. + return unaryResponseTcs.Task.Result; + } + catch (AggregateException ae) + { + throw ExceptionHelper.UnwrapRpcException(ae); + } } } diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs index 5a9d0039bc..e1cf64ca56 100644 --- a/src/csharp/Grpc.Core/RpcException.cs +++ b/src/csharp/Grpc.Core/RpcException.cs @@ -49,7 +49,8 @@ namespace Grpc.Core this.status = status; } - public Status Status { + public Status Status + { get { return status; diff --git a/src/csharp/Grpc.Core/ServerCallHandler.cs b/src/csharp/Grpc.Core/ServerCallHandler.cs index 1296947f34..289f97aece 100644 --- a/src/csharp/Grpc.Core/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/ServerCallHandler.cs @@ -111,6 +111,8 @@ namespace Grpc.Core var finishedTask = asyncCall.ServerSideStreamingRequestCallAsync(new NullObserver<byte[]>()); + // TODO: this makes the call finish before all reads can be done which causes trouble + // in AsyncCall.HandleReadFinished callback. Revisit this. asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, "No such method.")).Wait(); finishedTask.Wait(); diff --git a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs new file mode 100644 index 0000000000..18702e1cc4 --- /dev/null +++ b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs @@ -0,0 +1,57 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; + +namespace Grpc.Core.Utils +{ + public static class ExceptionHelper + { + /// <summary> + /// If inner exceptions contain RpcException, rethrows it. + /// Otherwise, rethrows the original aggregate exception. + /// Always throws, the exception return type is here only to make the. + /// </summary> + public static Exception UnwrapRpcException(AggregateException ae) { + foreach (var e in ae.InnerExceptions) + { + if (e is RpcException) + { + throw e; + } + } + throw ae; + } + } +} + -- GitLab