diff --git a/src/csharp/Grpc.Core.Api/Status.cs b/src/csharp/Grpc.Core.Api/Status.cs index 72d9e5371b8..32f79f74cc1 100644 --- a/src/csharp/Grpc.Core.Api/Status.cs +++ b/src/csharp/Grpc.Core.Api/Status.cs @@ -14,6 +14,8 @@ // limitations under the License. #endregion +using System; + namespace Grpc.Core { /// @@ -47,12 +49,12 @@ namespace Grpc.Core /// /// Status code. /// Detail. - /// Optional internal error string. - public Status(StatusCode statusCode, string detail, string debugErrorString) + /// Optional internal error details. + public Status(StatusCode statusCode, string detail, Exception debugErrorException) { StatusCode = statusCode; Detail = detail; - DebugErrorString = debugErrorString; + DebugErrorException = debugErrorException; } /// @@ -70,20 +72,20 @@ namespace Grpc.Core /// This field will be only populated on a client and its value is generated locally, /// based on the internal state of the gRPC client stack (i.e. the value is never sent over the wire). /// Note that this field is available only for debugging purposes, the application logic should - /// never rely on values of this field (it should should StatusCode and Detail instead). + /// never rely on values of this field (it should use StatusCode and Detail instead). /// Example: when a client fails to connect to a server, this field may provide additional details /// why the connection to the server has failed. /// - public string DebugErrorString { get; } + public Exception DebugErrorException { get; } /// /// Returns a that represents the current . /// public override string ToString() { - if (DebugErrorString != null) + if (DebugErrorException != null) { - return $"Status(StatusCode=\"{StatusCode}\", Detail=\"{Detail}\", DebugErrorString=\"{DebugErrorString}\")"; + return $"Status(StatusCode=\"{StatusCode}\", Detail=\"{Detail}\", DebugErrorException=\"{DebugErrorException}\")"; } return $"Status(StatusCode=\"{StatusCode}\", Detail=\"{Detail}\")"; } diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index a12ed31e95d..7072851732a 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -144,18 +144,18 @@ namespace Grpc.Core.Tests { helper.UnaryHandler = new UnaryServerMethod((request, context) => { - context.Status = new Status(StatusCode.Unauthenticated, "", "this DebugErrorString value should not be transmitted to the client"); + context.Status = new Status(StatusCode.Unauthenticated, "", new DebugErrorException("this DebugErrorString value should not be transmitted to the client")); return Task.FromResult(""); }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); - StringAssert.Contains("Error received from peer", ex.Status.DebugErrorString, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?"); + StringAssert.Contains("Error received from peer", ex.Status.DebugErrorException.Message, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?"); Assert.AreEqual(0, ex.Trailers.Count); var ex2 = Assert.ThrowsAsync(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); - StringAssert.Contains("Error received from peer", ex2.Status.DebugErrorString, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?"); + StringAssert.Contains("Error received from peer", ex2.Status.DebugErrorException.Message, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?"); Assert.AreEqual(0, ex2.Trailers.Count); } diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs index a8470af549e..e00f153c21f 100644 --- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs @@ -93,7 +93,7 @@ namespace Grpc.Core.Internal IntPtr detailsPtr = Native.grpcsharp_batch_context_recv_status_on_client_details(this, out detailsLength); string details = MarshalUtils.PtrToStringUTF8(detailsPtr, (int)detailsLength.ToUInt32()); string debugErrorString = Marshal.PtrToStringAnsi(Native.grpcsharp_batch_context_recv_status_on_client_error_string(this)); - var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details, debugErrorString); + var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details, debugErrorString != null ? new DebugErrorException(debugErrorString) : null); IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this); var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr); diff --git a/src/csharp/Grpc.Core/Internal/DebugErrorException.cs b/src/csharp/Grpc.Core/Internal/DebugErrorException.cs new file mode 100644 index 00000000000..a8c4561c4bf --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/DebugErrorException.cs @@ -0,0 +1,35 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal +{ + /// + /// Represents error details provides by C-core's debug_error_string + /// + internal class DebugErrorException : Exception + { + public DebugErrorException(string message) : base(message) + { + } + } +}