| | | 1 | | // Copyright (c) ZeroC, Inc. |
| | | 2 | | |
| | | 3 | | using IceRpc.Internal; |
| | | 4 | | |
| | | 5 | | namespace IceRpc; |
| | | 6 | | |
| | | 7 | | /// <summary>Represents an exception thrown while dispatching a request. It's encoded as a response with a status code |
| | | 8 | | /// greater than <see cref="StatusCode.Ok" />.</summary> |
| | | 9 | | public sealed class DispatchException : Exception |
| | | 10 | | { |
| | | 11 | | /// <summary>Gets or sets a value indicating whether the exception should be converted into a <see |
| | | 12 | | /// cref="DispatchException" /> with status code <see cref="StatusCode.InternalError" /> when thrown from a |
| | | 13 | | /// dispatch.</summary> |
| | | 14 | | /// <value>When <see langword="true" />, this exception is converted into dispatch exception with status code <see |
| | | 15 | | /// cref="StatusCode.InternalError" /> just before it's encoded. Defaults to <see langword="true" /> for an |
| | | 16 | | /// exception decoded from an <see cref="IncomingResponse" />, and <see langword="false" /> for an exception created |
| | | 17 | | /// by the application using a constructor of <see cref="DispatchException" />.</value> |
| | 72 | 18 | | public bool ConvertToInternalError { get; set; } |
| | | 19 | | |
| | | 20 | | /// <summary>Gets the error message of the failure response that carries this exception.</summary> |
| | | 21 | | /// <value>The <see cref="Exception.Message" /> of this exception, followed by the type and the message of its |
| | | 22 | | /// <see cref="Exception.InnerException" /> when there is one.</value> |
| | 33 | 23 | | public string ErrorMessage => DispatchErrorMessage.Compose(Message, InnerException); |
| | | 24 | | |
| | | 25 | | /// <summary>Gets the status code.</summary> |
| | | 26 | | /// <value>The <see cref="IceRpc.StatusCode" /> of this exception.</value> |
| | 66 | 27 | | public StatusCode StatusCode { get; } |
| | | 28 | | |
| | | 29 | | /// <summary>Constructs a new instance of <see cref="DispatchException" />.</summary> |
| | | 30 | | /// <param name="statusCode">The status code of this exception. It must be greater than <see |
| | | 31 | | /// cref="StatusCode.Ok" />.</param> |
| | | 32 | | /// <param name="message">A message that describes the exception.</param> |
| | | 33 | | /// <param name="innerException">The exception that is the cause of the current exception.</param> |
| | | 34 | | /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="statusCode" /> is equal to <see |
| | | 35 | | /// cref="StatusCode.Ok" />.</exception> |
| | | 36 | | public DispatchException( |
| | | 37 | | StatusCode statusCode, |
| | | 38 | | string? message = null, |
| | | 39 | | Exception? innerException = null) |
| | 62 | 40 | | : base(message ?? $"The dispatch failed with status code {statusCode}.", innerException) => |
| | 62 | 41 | | StatusCode = statusCode > StatusCode.Ok ? statusCode : |
| | 62 | 42 | | throw new ArgumentOutOfRangeException( |
| | 62 | 43 | | nameof(statusCode), |
| | 62 | 44 | | $"The status code of a {nameof(DispatchException)} must be greater than {nameof(StatusCode.Ok)}."); |
| | | 45 | | |
| | | 46 | | /// <summary>Converts an exception thrown by a dispatch into a dispatch exception.</summary> |
| | | 47 | | /// <param name="exception">The exception thrown by the dispatch.</param> |
| | | 48 | | /// <returns><paramref name="exception" /> when it is a <see cref="DispatchException" /> with |
| | | 49 | | /// <see cref="ConvertToInternalError" /> set to <see langword="false" />; otherwise, a new dispatch exception with |
| | | 50 | | /// <paramref name="exception" /> as its inner exception and a status code that depends on the type of |
| | | 51 | | /// <paramref name="exception" />: <see cref="StatusCode.InvalidData" /> for an <see cref="InvalidDataException" />, |
| | | 52 | | /// <see cref="StatusCode.NotSupported" /> for a <see cref="NotSupportedException" />, |
| | | 53 | | /// <see cref="StatusCode.TruncatedPayload" /> for an <see cref="IceRpcException" /> with error |
| | | 54 | | /// <see cref="IceRpcError.TruncatedData" />, and <see cref="StatusCode.InternalError" /> for any other exception, |
| | | 55 | | /// including a <see cref="DispatchException" /> with <see cref="ConvertToInternalError" /> set to |
| | | 56 | | /// <see langword="true" />.</returns> |
| | | 57 | | public static DispatchException FromException(Exception exception) => |
| | 36 | 58 | | exception is DispatchException { ConvertToInternalError: false } dispatchException ? |
| | 36 | 59 | | dispatchException : |
| | 36 | 60 | | new DispatchException( |
| | 36 | 61 | | exception switch |
| | 36 | 62 | | { |
| | 4 | 63 | | InvalidDataException => StatusCode.InvalidData, |
| | 3 | 64 | | NotSupportedException => StatusCode.NotSupported, |
| | 6 | 65 | | IceRpcException { IceRpcError: IceRpcError.TruncatedData } => StatusCode.TruncatedPayload, |
| | 12 | 66 | | _ => StatusCode.InternalError |
| | 36 | 67 | | }, |
| | 36 | 68 | | innerException: exception); |
| | | 69 | | } |