/// <summary> /// Adds the messages to response trailers as a binary byte array. /// </summary> private static void AddMessagesToResponseTrailers(GrpcServiceBase service, MessageItemCollection?messages) { if (messages == null || messages.Count == 0) { return; } using var ms = new MemoryStream(); using var bdw = new BsonDataWriter(ms); var js = new JsonSerializer(); js.Serialize(bdw, new GrpcMessages { Messages = messages }); service.Context.ResponseTrailers.Add(GrpcConsts.MessagesHeaderName, ms.ToArray()); }
/// <summary> /// Create <see cref="grpc.Status"/> from the <see cref="Exception"/>. /// </summary> /// <param name="service">The <see cref="GrpcServiceBase"/>.</param> /// <param name="exception">The <see cref="Exception"/>.</param> /// <returns>The corresponding <see cref="grpc.Status"/>.</returns> public static void ThrowRpcExceptionFromException(GrpcServiceBase service, Exception exception) { if (service == null) { throw new ArgumentNullException(nameof(service)); } if (exception == null) { throw new ArgumentNullException(nameof(exception)); } IBusinessException?ex = null; // Unwind to a known exception type if we can. if (exception is IBusinessException) { ex = exception as IBusinessException; } if (ex == null && exception is AggregateException aex) { if (aex.InnerExceptions.Count == 1 && aex.InnerException is IBusinessException) { ex = aex.InnerException as IBusinessException; } } // Where it is not known then "action" as unhandled. if (ex != null) { if (ex.ShouldBeLogged) { Diagnostics.Logger.Create <GrpcServiceBase>().LogError(exception, UnhandledExceptionMessage); } grpc.Status?status = ex.ErrorType switch { ErrorType.AuthenticationError => new grpc.Status(grpc.StatusCode.Unauthenticated, exception.Message), ErrorType.AuthorizationError => new grpc.Status(grpc.StatusCode.PermissionDenied, exception.Message), ErrorType.BusinessError => new grpc.Status(grpc.StatusCode.InvalidArgument, exception.Message), ErrorType.ConcurrencyError => new grpc.Status(grpc.StatusCode.Aborted, exception.Message), ErrorType.ConflictError => new grpc.Status(grpc.StatusCode.FailedPrecondition, exception.Message), ErrorType.DuplicateError => new grpc.Status(grpc.StatusCode.AlreadyExists, exception.Message), ErrorType.NotFoundError => new grpc.Status(grpc.StatusCode.NotFound, exception.Message), ErrorType.ValidationError => new grpc.Status(grpc.StatusCode.InvalidArgument, exception.Message), _ => null, }; if (status != null) { service.Context.ResponseTrailers.Add(GrpcConsts.ErrorTypeHeaderName, ex.ErrorType.ToString()); service.Context.ResponseTrailers.Add(GrpcConsts.ErrorCodeHeaderName, ((int)ex.ErrorType).ToString(System.Globalization.CultureInfo.InvariantCulture)); if (ex is ValidationException vex) { AddMessagesToResponseTrailers(service, vex.Messages); } throw new grpc.RpcException(status.Value); } } if (ex == null) { Diagnostics.Logger.Create <GrpcServiceBase>().LogError(exception, UnhandledExceptionMessage); } throw new grpc.RpcException(new grpc.Status(UnhandledExceptionStatusCode, IncludeUnhandledExceptionInResponse ? exception.ToString() : UnhandledExceptionMessage)); }