diff --git a/Source/Euonia.Bus.Abstract/MessageContext.cs b/Source/Euonia.Bus.Abstract/MessageContext.cs index 3028caa..4fece29 100644 --- a/Source/Euonia.Bus.Abstract/MessageContext.cs +++ b/Source/Euonia.Bus.Abstract/MessageContext.cs @@ -44,7 +44,7 @@ public MessageContext(IRoutedMessage pack) /// /// Invoked while message was handled and replied to dispatcher. /// - public event EventHandler OnResponse + public event EventHandler Responded { add => _events.AddEventHandler(value); remove => _events.RemoveEventHandler(value); @@ -59,6 +59,15 @@ public event EventHandler Completed remove => _events.RemoveEventHandler(value); } + /// + /// Invoked while message handling was failed. + /// + public event EventHandler Failed + { + add => _events.AddEventHandler(value); + remove => _events.RemoveEventHandler(value); + } + /// public object Message { get; } @@ -106,7 +115,7 @@ public string Authorization /// The message to reply. public void Response(object message) { - _events.HandleEvent(this, new MessageRepliedEventArgs(message), nameof(OnResponse)); + _events.HandleEvent(this, new MessageRepliedEventArgs(message), nameof(Responded)); } /// @@ -119,6 +128,15 @@ public void Response(TMessage message) Response((object)message); } + /// + /// Called after the message handling was failed. + /// + /// + public void Failure(Exception exception) + { + _events.HandleEvent(this, exception, nameof(Failed)); + } + /// /// Called after the message has been handled. /// This operate will raised up the event. diff --git a/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs b/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs index b58fc64..28123bb 100644 --- a/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs +++ b/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs @@ -39,6 +39,11 @@ public async Task SendAsync(RoutedMessage message, Cancellat cancellationToken.Register(() => taskCompletion.SetCanceled(cancellationToken)); } + context.Failed += (_, exception) => + { + taskCompletion.TrySetException(exception); + }; + context.Completed += (_, _) => { taskCompletion.SetResult(); @@ -68,13 +73,17 @@ public async Task SendAsync(RoutedMessage taskCompletion.TrySetCanceled(), false); } - context.OnResponse += (_, args) => + context.Responded += (_, args) => { taskCompletion.SetResult((TResponse)args.Result); }; + context.Failed += (_, exception) => + { + taskCompletion.TrySetException(exception); + }; context.Completed += (_, _) => { - taskCompletion.TrySetResult(default); + taskCompletion.TryCompleteFromCompletedTask(Task.FromResult(default(TResponse))); }; StrongReferenceMessenger.Default.UnsafeSend(pack, message.Channel); diff --git a/Source/Euonia.Bus.RabbitMq/Constants.cs b/Source/Euonia.Bus.RabbitMq/Constants.cs index a1d7b2a..71b75ee 100644 --- a/Source/Euonia.Bus.RabbitMq/Constants.cs +++ b/Source/Euonia.Bus.RabbitMq/Constants.cs @@ -8,7 +8,8 @@ internal class Constants { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ConstructorHandling = ConstructorHandling.Default, - MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead + MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead, + TypeNameHandling = TypeNameHandling.Auto }; public class MessageHeaders diff --git a/Source/Euonia.Bus.RabbitMq/RabbitMqDispatcher.cs b/Source/Euonia.Bus.RabbitMq/RabbitMqDispatcher.cs index 2f80372..9694410 100644 --- a/Source/Euonia.Bus.RabbitMq/RabbitMqDispatcher.cs +++ b/Source/Euonia.Bus.RabbitMq/RabbitMqDispatcher.cs @@ -48,56 +48,88 @@ public async Task PublishAsync(RoutedMessage message, Cancel props.Type = typeName; await Policy.Handle() - .Or() - .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(3), (exception, _, retryCount, _) => - { - _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); - }) - .ExecuteAsync(async () => - { - var messageBody = await SerializeAsync(message, cancellationToken); - - channel.ExchangeDeclare(_options.ExchangeName, _options.ExchangeType); - channel.BasicPublish(_options.ExchangeName, $"{_options.TopicName}${message.Channel}$", props, messageBody); - - Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); - }); + .Or() + .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(3), (exception, _, retryCount, _) => + { + _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); + }) + .ExecuteAsync(async () => + { + var messageBody = await SerializeAsync(message, cancellationToken); + + channel.ExchangeDeclare(_options.ExchangeName, _options.ExchangeType); + channel.BasicPublish(_options.ExchangeName, $"{_options.TopicName}${message.Channel}$", props, messageBody); + + Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); + }); } /// public async Task SendAsync(RoutedMessage message, CancellationToken cancellationToken = default) where TMessage : class { - using var channel = _connection.CreateChannel(); + var task = new TaskCompletionSource(); var requestQueueName = $"{_options.QueueName}${message.Channel}$"; + using var channel = _connection.CreateChannel(); + CheckQueue(channel, requestQueueName); + var responseQueueName = channel.QueueDeclare().QueueName; + var consumer = new EventingBasicConsumer(channel); + + consumer.Received += OnReceived; + var typeName = message.GetTypeName(); var props = channel.CreateBasicProperties(); props.Headers ??= new Dictionary(); props.Headers[Constants.MessageHeaders.MessageType] = typeName; props.Type = typeName; + props.CorrelationId = message.CorrelationId; + props.ReplyTo = responseQueueName; await Policy.Handle() - .Or() - .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(3), (exception, _, retryCount, _) => - { - _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); - }) - .ExecuteAsync(async () => - { - var messageBody = await SerializeAsync(message, cancellationToken); - - channel.BasicPublish("", requestQueueName, props, messageBody); - - Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); - }); + .Or() + .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(1), (exception, _, retryCount, _) => + { + _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); + }) + .ExecuteAsync(async () => + { + var messageBody = await SerializeAsync(message, cancellationToken); + channel.BasicPublish("", requestQueueName, props, messageBody); + channel.BasicConsume(consumer, responseQueueName, true); + + Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); + }); + + await task.Task; + consumer.Received -= OnReceived; + + void OnReceived(object sender, BasicDeliverEventArgs args) + { + if (args.BasicProperties.CorrelationId != message.CorrelationId) + { + return; + } + + var body = args.Body.ToArray(); + var response = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(body), Constants.SerializerSettings); + if (response.IsSuccess) + { + task.SetResult(response.Result); + } + else + { + task.SetException(response.Error); + } + } } /// - public async Task SendAsync(RoutedMessage message, CancellationToken cancellationToken = default) where TMessage : class + public async Task SendAsync(RoutedMessage message, CancellationToken cancellationToken = default) + where TMessage : class { var task = new TaskCompletionSource(); @@ -122,19 +154,19 @@ public async Task SendAsync(RoutedMessage() - .Or() - .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(1), (exception, _, retryCount, _) => - { - _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); - }) - .ExecuteAsync(async () => - { - var messageBody = await SerializeAsync(message, cancellationToken); - channel.BasicPublish("", requestQueueName, props, messageBody); - channel.BasicConsume(consumer, responseQueueName, true); - - Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); - }); + .Or() + .WaitAndRetryAsync(_options.MaxFailureRetries, _ => TimeSpan.FromSeconds(1), (exception, _, retryCount, _) => + { + _logger.LogError(exception, "Retry:{RetryCount}, {Message}", retryCount, exception.Message); + }) + .ExecuteAsync(async () => + { + var messageBody = await SerializeAsync(message, cancellationToken); + channel.BasicPublish("", requestQueueName, props, messageBody); + channel.BasicConsume(consumer, responseQueueName, true); + + Delivered?.Invoke(this, new MessageDispatchedEventArgs(message.Data, null)); + }); var result = await task.Task; consumer.Received -= OnReceived; @@ -148,9 +180,8 @@ void OnReceived(object sender, BasicDeliverEventArgs args) } var body = args.Body.ToArray(); - var response = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(body), Constants.SerializerSettings); - - task.SetResult(response); + var response = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(body), Constants.SerializerSettings); + task.SetResult(response.Result); } } diff --git a/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs b/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs index 62da174..a205f69 100644 --- a/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs +++ b/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs @@ -40,6 +40,7 @@ internal override void Start(string channel) { Connection.TryConnect(); } + Channel = Connection.CreateChannel(); Channel.QueueDeclare(queueName, true, false, false, null); @@ -65,27 +66,40 @@ protected override async void HandleMessageReceived(object sender, BasicDeliverE OnMessageReceived(new MessageReceivedEventArgs(message.Data, context)); var taskCompletion = new TaskCompletionSource(); - context.OnResponse += (_, a) => + context.Responded += (_, a) => { taskCompletion.TrySetResult(a.Result); }; + context.Failed += (_, exception) => + { + taskCompletion.TrySetException(exception); + }; context.Completed += (_, _) => { taskCompletion.TryCompleteFromCompletedTask(Task.FromResult(default(object))); }; + RabbitMqReply reply; + await Handler.HandleAsync(message.Channel, message.Data, context); - var result = await taskCompletion.Task; + try + { + var result = await taskCompletion.Task; + reply = RabbitMqReply.Success(result); + } + catch (Exception exception) + { + reply = RabbitMqReply.Failure(exception); + } if (!string.IsNullOrEmpty(props.CorrelationId) || !string.IsNullOrWhiteSpace(props.ReplyTo)) { var replyProps = Channel.CreateBasicProperties(); replyProps.Headers ??= new Dictionary(); - replyProps.Headers.Add(Constants.MessageHeaders.MessageType, result.GetType().GetFullNameWithAssemblyName()); replyProps.CorrelationId = props.CorrelationId; - var response = SerializeMessage(result); + var response = SerializeMessage(reply); Channel.BasicPublish(string.Empty, props.ReplyTo, replyProps, response); } diff --git a/Source/Euonia.Bus.RabbitMq/RabbitMqReply.cs b/Source/Euonia.Bus.RabbitMq/RabbitMqReply.cs new file mode 100644 index 0000000..62d9dbb --- /dev/null +++ b/Source/Euonia.Bus.RabbitMq/RabbitMqReply.cs @@ -0,0 +1,45 @@ +namespace Nerosoft.Euonia.Bus.RabbitMq; + +internal class RabbitMqReply +{ + /// + /// Gets or sets the result. + /// + public TResult Result { get; set; } + + /// + /// Gets or sets the error. + /// + public Exception Error { get; set; } + + /// + /// Gets a value indicating whether this message handing is success. + /// + public bool IsSuccess => Error == null; + + /// + /// + /// + /// + /// + public static RabbitMqReply Success(TResult result) + { + return new RabbitMqReply + { + Result = result + }; + } + + /// + /// + /// + /// + /// + public static RabbitMqReply Failure(Exception error) + { + return new RabbitMqReply + { + Error = error + }; + } +} \ No newline at end of file diff --git a/Source/Euonia.Bus/Core/HandlerContext.cs b/Source/Euonia.Bus/Core/HandlerContext.cs index 09e94ef..ec1c6c3 100644 --- a/Source/Euonia.Bus/Core/HandlerContext.cs +++ b/Source/Euonia.Bus/Core/HandlerContext.cs @@ -86,49 +86,48 @@ public virtual async Task HandleAsync(object message, MessageContext context, Ca /// public virtual async Task HandleAsync(string channel, object message, MessageContext context, CancellationToken cancellationToken = default) { - if (message == null) + try { - return; - } + if (message == null) + { + return; + } - var tasks = new List(); - using var scope = _provider.GetRequiredService().CreateScope(); + var tasks = new List(); + using var scope = _provider.GetRequiredService().CreateScope(); - if (!_handlerContainer.TryGetValue(channel, out var handling)) - { - throw new InvalidOperationException("No handler registered for message"); - } + if (!_handlerContainer.TryGetValue(channel, out var handling)) + { + throw new InvalidOperationException("No handler registered for message"); + } - // Get handler instance from service provider using Expression Tree + // Get handler instance from service provider using Expression Tree - foreach (var factory in handling) - { - var handler = factory(scope.ServiceProvider); - tasks.Add(handler(message, context, cancellationToken)); - // var handler = ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, handlerType); - // - // var arguments = GetMethodArguments(handleMethod, message, context, cancellationToken); - // if (arguments == null) - // { - // _logger.LogWarning("Method '{Name}' parameter number not matches", handleMethod.Name); - // } - // else - // { - // tasks.Add(Invoke(handleMethod, handler, arguments)); - // } - } + foreach (var factory in handling) + { + var handler = factory(scope.ServiceProvider); + tasks.Add(handler(message, context, cancellationToken)); + } + + if (tasks.Count == 0) + { + return; + } - if (tasks.Count == 0) + await Task.WhenAll(tasks).ContinueWith(task => + { + task.WaitAndUnwrapException(cancellationToken); + _logger?.LogInformation("Message {Id} was completed handled", context.MessageId); + }, cancellationToken); + } + catch (Exception exception) { - return; + context.Failure(exception); } - - await Task.WhenAll(tasks).ContinueWith(_ => + finally { - _logger?.LogInformation("Message {Id} was completed handled", context.MessageId); - }, cancellationToken); - - context.Dispose(); + context.Dispose(); + } } #endregion diff --git a/Source/Euonia.Core/Exceptions/BadGatewayException.cs b/Source/Euonia.Core/Exceptions/BadGatewayException.cs index 2548c03..16ba524 100644 --- a/Source/Euonia.Core/Exceptions/BadGatewayException.cs +++ b/Source/Euonia.Core/Exceptions/BadGatewayException.cs @@ -9,31 +9,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.BadGateway)] public class BadGatewayException : Exception { - private const string DEFAULT_MESSAGE = "Bad Gateway"; + private const string DEFAULT_MESSAGE = "Bad Gateway"; - /// - public BadGatewayException() - : base(DEFAULT_MESSAGE) - { - } + /// + public BadGatewayException() + : base(DEFAULT_MESSAGE) + { + } -#if !NET8_0_OR_GREATER /// - public BadGatewayException(SerializationInfo info, StreamingContext context) - : base(info, context) + public BadGatewayException(string message) + : base(message) { } -#endif - /// - public BadGatewayException(string message) - : base(message) - { - } + /// + public BadGatewayException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - public BadGatewayException(string message, Exception innerException) - : base(message, innerException) - { - } +#pragma warning disable SYSLIB0051 + /// + public BadGatewayException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/BadRequestException.cs b/Source/Euonia.Core/Exceptions/BadRequestException.cs index 8f3f991..9a112f0 100644 --- a/Source/Euonia.Core/Exceptions/BadRequestException.cs +++ b/Source/Euonia.Core/Exceptions/BadRequestException.cs @@ -16,14 +16,6 @@ public BadRequestException() { } -#if !NET8_0_OR_GREATER - /// - public BadRequestException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -#endif - /// public BadRequestException(string message) : base(message) @@ -35,4 +27,12 @@ public BadRequestException(string message, Exception innerException) : base(message, innerException) { } + +#pragma warning disable SYSLIB0051 + /// + public BadRequestException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/BusinessException.cs b/Source/Euonia.Core/Exceptions/BusinessException.cs index 450f3d5..e941a8a 100644 --- a/Source/Euonia.Core/Exceptions/BusinessException.cs +++ b/Source/Euonia.Core/Exceptions/BusinessException.cs @@ -50,7 +50,7 @@ public BusinessException(string code, string message, Exception innerException) _code = code; } -#if !NET8_0_OR_GREATER +#pragma warning disable SYSLIB0051 /// public BusinessException(SerializationInfo info, StreamingContext context) : base(info, context) @@ -58,11 +58,14 @@ public BusinessException(SerializationInfo info, StreamingContext context) _code = info.GetString(nameof(Code)); } +#pragma warning disable CS0672 // Member overrides obsolete member /// public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue(nameof(Code), _code, typeof(string)); } -#endif +#pragma warning restore CS0672 // Member overrides obsolete member + +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/ConfigurationException.cs b/Source/Euonia.Core/Exceptions/ConfigurationException.cs index 9454633..3361af1 100644 --- a/Source/Euonia.Core/Exceptions/ConfigurationException.cs +++ b/Source/Euonia.Core/Exceptions/ConfigurationException.cs @@ -32,11 +32,11 @@ public ConfigurationException(string message, Exception innerException) { } -#if !NET8_0_OR_GREATER +#pragma warning disable SYSLIB0051 /// public ConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context) { } -#endif +#pragma warning restore SYSLIB0051 } diff --git a/Source/Euonia.Core/Exceptions/ConflictException.cs b/Source/Euonia.Core/Exceptions/ConflictException.cs index 0407ca8..0fd4cbd 100644 --- a/Source/Euonia.Core/Exceptions/ConflictException.cs +++ b/Source/Euonia.Core/Exceptions/ConflictException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.Conflict)] public class ConflictException : Exception { - private const string DEFAULT_MESSAGE = "Conflict"; + private const string DEFAULT_MESSAGE = "Conflict"; - /// - public ConflictException() - : base(DEFAULT_MESSAGE) - { - } + /// + public ConflictException() + : base(DEFAULT_MESSAGE) + { + } -#if !NET8_0_OR_GREATER /// - public ConflictException(SerializationInfo info, StreamingContext context) - : base(info, context) + public ConflictException(string message) + : base(message) { } -#endif - /// - public ConflictException(string message) - : base(message) - { - } + /// + public ConflictException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - public ConflictException(string message, Exception innerException) - : base(message, innerException) - { - } +#pragma warning disable SYSLIB0051 + /// + public ConflictException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/ForbiddenException.cs b/Source/Euonia.Core/Exceptions/ForbiddenException.cs index bfa814e..f4fe3da 100644 --- a/Source/Euonia.Core/Exceptions/ForbiddenException.cs +++ b/Source/Euonia.Core/Exceptions/ForbiddenException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.Forbidden)] public class ForbiddenException : Exception { - private const string DEFAULT_MESSAGE = "Forbidden"; + private const string DEFAULT_MESSAGE = "Forbidden"; - /// - public ForbiddenException() - : base(DEFAULT_MESSAGE) - { - } + /// + public ForbiddenException() + : base(DEFAULT_MESSAGE) + { + } -#if !NET8_0_OR_GREATER /// - public ForbiddenException(SerializationInfo info, StreamingContext context) - : base(info, context) + public ForbiddenException(string message) + : base(message) { } -#endif - /// - public ForbiddenException(string message) - : base(message) - { - } + /// + public ForbiddenException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - public ForbiddenException(string message, Exception innerException) - : base(message, innerException) - { - } +#pragma warning disable SYSLIB0051 + /// + public ForbiddenException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/GatewayTimeoutException.cs b/Source/Euonia.Core/Exceptions/GatewayTimeoutException.cs index 3997440..50f97ac 100644 --- a/Source/Euonia.Core/Exceptions/GatewayTimeoutException.cs +++ b/Source/Euonia.Core/Exceptions/GatewayTimeoutException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.GatewayTimeout)] public class GatewayTimeoutException : Exception { - private const string DEFAULT_MESSAGE = "Gateway Timeout"; + private const string DEFAULT_MESSAGE = "Gateway Timeout"; - /// - public GatewayTimeoutException() - : base(DEFAULT_MESSAGE) - { - } - -#if !NET8_0_OR_GREATER /// - public GatewayTimeoutException(SerializationInfo info, StreamingContext context) - : base(info, context) + public GatewayTimeoutException() + : base(DEFAULT_MESSAGE) { - } -#endif + } /// public GatewayTimeoutException(string message) - : base(message) - { - } + : base(message) + { + } - /// - public GatewayTimeoutException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + public GatewayTimeoutException(string message, Exception innerException) + : base(message, innerException) + { + } + +#pragma warning disable SYSLIB0051 + /// + public GatewayTimeoutException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/HttpStatusException.cs b/Source/Euonia.Core/Exceptions/HttpStatusException.cs index cc2ba9a..68f28fb 100644 --- a/Source/Euonia.Core/Exceptions/HttpStatusException.cs +++ b/Source/Euonia.Core/Exceptions/HttpStatusException.cs @@ -8,26 +8,17 @@ namespace System; [Serializable] public class HttpStatusException : Exception { - private readonly HttpStatusCode _statusCode; + private readonly HttpStatusCode _statusCode; - /// - /// Initializes a new instance of the class. - /// - /// - public HttpStatusException(HttpStatusCode statusCode) - : base(statusCode.ToString()) - { - _statusCode = statusCode; - } - -#if !NET8_0_OR_GREATER - /// - public HttpStatusException(SerializationInfo info, StreamingContext context) - : base(info, context) + /// + /// Initializes a new instance of the class. + /// + /// + public HttpStatusException(HttpStatusCode statusCode) + : base(statusCode.ToString()) { - _statusCode = (HttpStatusCode)info.GetInt32(nameof(StatusCode)); - } -#endif + _statusCode = statusCode; + } /// /// Initializes a new instance of the class. @@ -35,34 +26,45 @@ public HttpStatusException(SerializationInfo info, StreamingContext context) /// /// public HttpStatusException(HttpStatusCode statusCode, string message) - : base(message) - { - _statusCode = statusCode; - } + : base(message) + { + _statusCode = statusCode; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public HttpStatusException(HttpStatusCode statusCode, string message, Exception innerException) + : base(message, innerException) + { + _statusCode = statusCode; + } + + /// + /// Gets the HTTP status code. + /// + public virtual HttpStatusCode StatusCode => _statusCode; - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public HttpStatusException(HttpStatusCode statusCode, string message, Exception innerException) - : base(message, innerException) - { - _statusCode = statusCode; - } +#pragma warning disable SYSLIB0051 + /// + public HttpStatusException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _statusCode = (HttpStatusCode)info.GetInt32(nameof(StatusCode)); + } -#if !NET8_0_OR_GREATER +#pragma warning disable CS0672 /// public override void GetObjectData(SerializationInfo info, StreamingContext context) + { base.GetObjectData(info, context); info.AddValue(nameof(StatusCode), (int)_statusCode, typeof(int)); - } -#endif + } +#pragma warning restore CS0672 - /// - /// Gets the HTTP status code. - /// - public virtual HttpStatusCode StatusCode => _statusCode; +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/InternalServerErrorException.cs b/Source/Euonia.Core/Exceptions/InternalServerErrorException.cs index 958b579..2122dec 100644 --- a/Source/Euonia.Core/Exceptions/InternalServerErrorException.cs +++ b/Source/Euonia.Core/Exceptions/InternalServerErrorException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.InternalServerError)] public class InternalServerErrorException : Exception { - private const string DEFAULT_MESSAGE = "Internal Server Error"; + private const string DEFAULT_MESSAGE = "Internal Server Error"; - /// - public InternalServerErrorException() - : base(DEFAULT_MESSAGE) - { - } - -#if !NET8_0_OR_GREATER /// - public InternalServerErrorException(SerializationInfo info, StreamingContext context) - : base(info, context) + public InternalServerErrorException() + : base(DEFAULT_MESSAGE) { - } -#endif + } /// public InternalServerErrorException(string message) - : base(message) - { - } + : base(message) + { + } - /// - public InternalServerErrorException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + public InternalServerErrorException(string message, Exception innerException) + : base(message, innerException) + { + } + +#pragma warning disable SYSLIB0051 + /// + public InternalServerErrorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/InvalidValueException.cs b/Source/Euonia.Core/Exceptions/InvalidValueException.cs index 373ebaa..1055058 100644 --- a/Source/Euonia.Core/Exceptions/InvalidValueException.cs +++ b/Source/Euonia.Core/Exceptions/InvalidValueException.cs @@ -6,33 +6,33 @@ [Serializable] public class InvalidValueException : Exception { - /// - /// Initializes a new instance of the class. - /// - public InvalidValueException() - { - } + /// + /// Initializes a new instance of the class. + /// + public InvalidValueException() + { + } - /// - /// Initializes a new instance of the class with a specified error message. - /// - /// The error message. - public InvalidValueException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The error message. + public InvalidValueException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. - /// - /// The error message. - /// The inner exception that is the cause of this exception. - public InvalidValueException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message. + /// The inner exception that is the cause of this exception. + public InvalidValueException(string message, Exception innerException) + : base(message, innerException) + { + } -#if !NET8_0_OR_GREATER +#pragma warning disable SYSLIB0051 /// /// Initializes a new instance of the class with serialized data. /// @@ -41,6 +41,6 @@ public InvalidValueException(string message, Exception innerException) public InvalidValueException(SerializationInfo info, StreamingContext context) : base(info, context) { - } -#endif -} + } +#pragma warning restore SYSLIB0051 +} \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/MethodNotAllowedException.cs b/Source/Euonia.Core/Exceptions/MethodNotAllowedException.cs index acb887d..075b593 100644 --- a/Source/Euonia.Core/Exceptions/MethodNotAllowedException.cs +++ b/Source/Euonia.Core/Exceptions/MethodNotAllowedException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.MethodNotAllowed)] public class MethodNotAllowedException : Exception { - private const string DEFAULT_MESSAGE = "Method Not Allowed"; + private const string DEFAULT_MESSAGE = "Method Not Allowed"; - /// - public MethodNotAllowedException() - : base(DEFAULT_MESSAGE) - { - } - -#if !NET8_0_OR_GREATER /// - public MethodNotAllowedException(SerializationInfo info, StreamingContext context) - : base(info, context) + public MethodNotAllowedException() + : base(DEFAULT_MESSAGE) { - } -#endif + } /// public MethodNotAllowedException(string message) - : base(message) - { - } + : base(message) + { + } - /// - public MethodNotAllowedException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + public MethodNotAllowedException(string message, Exception innerException) + : base(message, innerException) + { + } + +#pragma warning disable SYSLIB0051 + /// + public MethodNotAllowedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/NotFoundException.cs b/Source/Euonia.Core/Exceptions/NotFoundException.cs index c5370f7..79db14e 100644 --- a/Source/Euonia.Core/Exceptions/NotFoundException.cs +++ b/Source/Euonia.Core/Exceptions/NotFoundException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.NotFound)] public class NotFoundException : Exception { - private const string DEFAULT_MESSAGE = "Not Found"; + private const string DEFAULT_MESSAGE = "Not Found"; - /// - public NotFoundException() - : base(DEFAULT_MESSAGE) - { - } + /// + public NotFoundException() + : base(DEFAULT_MESSAGE) + { + } - /// - public NotFoundException(string message) - : base(message) - { - } + /// + public NotFoundException(string message) + : base(message) + { + } - /// - public NotFoundException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + public NotFoundException(string message, Exception innerException) + : base(message, innerException) + { + } -#if !NET8_0_OR_GREATER +#pragma warning disable SYSLIB0051 /// public NotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { - } -#endif + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/RequestTimeoutException.cs b/Source/Euonia.Core/Exceptions/RequestTimeoutException.cs index a7450b6..40bd7c1 100644 --- a/Source/Euonia.Core/Exceptions/RequestTimeoutException.cs +++ b/Source/Euonia.Core/Exceptions/RequestTimeoutException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.RequestTimeout)] public class RequestTimeoutException : Exception { - private const string DEFAULT_MESSAGE = "Request Timeout"; + private const string DEFAULT_MESSAGE = "Request Timeout"; - /// - public RequestTimeoutException() - : base(DEFAULT_MESSAGE) - { - } + /// + public RequestTimeoutException() + : base(DEFAULT_MESSAGE) + { + } -#if !NET8_0_OR_GREATER /// - public RequestTimeoutException(SerializationInfo info, StreamingContext context) - : base(info, context) + public RequestTimeoutException(string message) + : base(message) { } -#endif - /// - public RequestTimeoutException(string message) - : base(message) - { - } + /// + public RequestTimeoutException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - public RequestTimeoutException(string message, Exception innerException) - : base(message, innerException) - { - } +#pragma warning disable SYSLIB0051 + /// + public RequestTimeoutException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/ServiceUnavailableException.cs b/Source/Euonia.Core/Exceptions/ServiceUnavailableException.cs index 0a93e36..31f430e 100644 --- a/Source/Euonia.Core/Exceptions/ServiceUnavailableException.cs +++ b/Source/Euonia.Core/Exceptions/ServiceUnavailableException.cs @@ -16,14 +16,6 @@ public ServiceUnavailableException() { } -#if !NET8_0_OR_GREATER - /// - public ServiceUnavailableException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -#endif - /// public ServiceUnavailableException(string message) : base(message) @@ -35,4 +27,12 @@ public ServiceUnavailableException(string message, Exception innerException) : base(message, innerException) { } + +#pragma warning disable SYSLIB0051 + /// + public ServiceUnavailableException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/TooManyRequestsException.cs b/Source/Euonia.Core/Exceptions/TooManyRequestsException.cs index f95e86f..db65b2a 100644 --- a/Source/Euonia.Core/Exceptions/TooManyRequestsException.cs +++ b/Source/Euonia.Core/Exceptions/TooManyRequestsException.cs @@ -8,31 +8,31 @@ namespace System; [Serializable, HttpStatusCode(HttpStatusCode.TooManyRequests)] public class TooManyRequestsException : Exception { - private const string DEFAULT_MESSAGE = "Too Many Requests"; + private const string DEFAULT_MESSAGE = "Too Many Requests"; - /// - public TooManyRequestsException() - : base(DEFAULT_MESSAGE) - { - } + /// + public TooManyRequestsException() + : base(DEFAULT_MESSAGE) + { + } -#if !NET8_0_OR_GREATER /// - public TooManyRequestsException(SerializationInfo info, StreamingContext context) - : base(info, context) + public TooManyRequestsException(string message) + : base(message) { } -#endif - /// - public TooManyRequestsException(string message) - : base(message) - { - } + /// + public TooManyRequestsException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - public TooManyRequestsException(string message, Exception innerException) - : base(message, innerException) - { - } +#pragma warning disable SYSLIB0051 + /// + public TooManyRequestsException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/UpgradeRequiredException.cs b/Source/Euonia.Core/Exceptions/UpgradeRequiredException.cs index 60ad60a..9df3a0d 100644 --- a/Source/Euonia.Core/Exceptions/UpgradeRequiredException.cs +++ b/Source/Euonia.Core/Exceptions/UpgradeRequiredException.cs @@ -16,14 +16,6 @@ public UpgradeRequiredException() { } -#if !NET8_0_OR_GREATER - /// - public UpgradeRequiredException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -#endif - /// public UpgradeRequiredException(string message) : base(message) @@ -35,4 +27,12 @@ public UpgradeRequiredException(string message, Exception innerException) : base(message, innerException) { } + +#pragma warning disable SYSLIB0051 + /// + public UpgradeRequiredException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/Exceptions/ValidationException.cs b/Source/Euonia.Core/Exceptions/ValidationException.cs index c49b203..a003660 100644 --- a/Source/Euonia.Core/Exceptions/ValidationException.cs +++ b/Source/Euonia.Core/Exceptions/ValidationException.cs @@ -8,31 +8,36 @@ [Serializable] public class ValidationException : Exception { - private readonly IEnumerable _errors; - - /// - /// Create a new . - /// - /// - /// - public ValidationException(string message, params ValidationResult[] results) - : base(message) - { - _errors = results?.ToList() ?? Enumerable.Empty(); - } - - /// - /// Creates a new - /// - /// - /// - public ValidationException(string message, IEnumerable errors) - : base(message) - { - _errors = errors; - } - -#if !NET8_0_OR_GREATER + private readonly IEnumerable _errors; + + /// + /// Create a new . + /// + /// + /// + public ValidationException(string message, params ValidationResult[] results) + : base(message) + { + _errors = results?.ToList() ?? Enumerable.Empty(); + } + + /// + /// Creates a new + /// + /// + /// + public ValidationException(string message, IEnumerable errors) + : base(message) + { + _errors = errors; + } + + /// + /// + /// + public virtual IEnumerable Errors => _errors; + +#pragma warning disable SYSLIB0051 /// public ValidationException(SerializationInfo info, StreamingContext context) : base(info, context) @@ -40,16 +45,15 @@ public ValidationException(SerializationInfo info, StreamingContext context) _errors = info.GetValue(nameof(Errors), typeof(IEnumerable)) as IEnumerable; } +#pragma warning disable CS0672 /// public override void GetObjectData(SerializationInfo info, StreamingContext context) + { base.GetObjectData(info, context); info.AddValue(nameof(Errors), _errors, typeof(IEnumerable)); } -#endif +#pragma warning restore CS0672 - /// - /// - /// - public virtual IEnumerable Errors => _errors; +#pragma warning restore SYSLIB0051 } \ No newline at end of file diff --git a/Source/Euonia.Core/System/Check.cs b/Source/Euonia.Core/System/Check.cs index 32d0f85..ebb3a30 100644 --- a/Source/Euonia.Core/System/Check.cs +++ b/Source/Euonia.Core/System/Check.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics; using System.Text.RegularExpressions; -using System.ComponentModel.DataAnnotations; using System.Globalization; /// diff --git a/Source/Euonia.Core/System/Empty.cs b/Source/Euonia.Core/System/Empty.cs new file mode 100644 index 0000000..53ef4ce --- /dev/null +++ b/Source/Euonia.Core/System/Empty.cs @@ -0,0 +1,28 @@ +namespace System; + +/// +/// Defines the . +/// +[Serializable] +public sealed class Empty : ISerializable +{ + private Empty() + { + } + + /// + /// Defines the Value. + /// + public static readonly Empty Value = new(); + + /// + public override string ToString() + { + return string.Empty; + } + + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + } +} \ No newline at end of file diff --git a/Source/Euonia.Core/Threading/Coordination/AsyncManualResetEvent.cs b/Source/Euonia.Core/Threading/Coordination/AsyncManualResetEvent.cs index 3042b35..2fdc817 100644 --- a/Source/Euonia.Core/Threading/Coordination/AsyncManualResetEvent.cs +++ b/Source/Euonia.Core/Threading/Coordination/AsyncManualResetEvent.cs @@ -95,9 +95,7 @@ public Task WaitAsync() public Task WaitAsync(CancellationToken cancellationToken) { var waitTask = WaitAsync(cancellationToken); - if (waitTask.IsCompleted) - return waitTask; - return waitTask.WaitAsync(cancellationToken); + return waitTask.IsCompleted ? waitTask : waitTask.WaitAsync(cancellationToken); } /// diff --git a/Source/Euonia.Domain/Commands/CommandStatus.cs b/Source/Euonia.Domain/Commands/CommandStatus.cs index d8b5571..4751724 100644 --- a/Source/Euonia.Domain/Commands/CommandStatus.cs +++ b/Source/Euonia.Domain/Commands/CommandStatus.cs @@ -5,58 +5,18 @@ /// public enum CommandStatus { - /// - /// Represents the command was successfully executed. - /// - Succeed, - - /// - /// Represents the command execution was canceled. - /// - Canceled, - - /// - /// Represents the specified data was not found. - /// - NotFound, - - /// - /// Represents the command execution - /// - Unauthorized, - - /// - /// - /// - Forbidden, - - /// - /// - /// - Timeout, - - /// - /// - /// - Internal, - - /// - /// - /// - Unimplemented, - - /// - /// - /// - Unavailable, - - /// - /// - /// - NotSupported, - - /// - /// - /// - Invalid + /// + /// Represents the command was successfully executed. + /// + Succeed, + + /// + /// Represents the command execution was failed. + /// + Failure, + + /// + /// Represents the command execution was canceled. + /// + Canceled, } \ No newline at end of file diff --git a/Source/Euonia.Domain/Extensions/CommandResponseExtensions.cs b/Source/Euonia.Domain/Extensions/CommandResponseExtensions.cs index 9f2e060..3639e28 100644 --- a/Source/Euonia.Domain/Extensions/CommandResponseExtensions.cs +++ b/Source/Euonia.Domain/Extensions/CommandResponseExtensions.cs @@ -5,169 +5,145 @@ /// public static class CommandResponseExtensions { - /// - /// Set response status to . - /// - /// - /// - public static CommandResponse Success(this CommandResponse response) - { - response.Status = CommandStatus.Succeed; - return response; - } + /// + /// Set response status to . + /// + /// + /// + public static CommandResponse Success(this CommandResponse response) + { + response.Status = CommandStatus.Succeed; + return response; + } - /// - /// - /// - /// - /// - /// - public static CommandResponse Failure(this CommandResponse response, Exception exception) - { - //response.Status = GetStatus(exception); - response.Error = exception; - response.Message = exception.Message; - response.Code = exception switch - { - BusinessException e => e.Code, - HttpRequestException e => $"HTTP{e.StatusCode}", - _ => response.Code - }; + /// + /// + /// + /// + /// + /// + public static CommandResponse Failure(this CommandResponse response, Exception exception) + { + response.Error = exception; + response.Message = exception.Message; + response.Code = exception switch + { + BusinessException e => e.Code, + HttpRequestException e => $"HTTP{e.StatusCode}", + _ => response.Code + }; + response.Status = exception is OperationCanceledException ? CommandStatus.Canceled : CommandStatus.Failure; - return response; - } + return response; + } - /// - /// Set response code and return the current instance. - /// - /// - /// - /// - public static CommandResponse WithCode(this CommandResponse response, string code) - { - response.Code = code; - return response; - } + /// + /// Set response code and return the current instance. + /// + /// + /// + /// + public static CommandResponse WithCode(this CommandResponse response, string code) + { + response.Code = code; + return response; + } - /// - /// Set response message and return the current instance. - /// - /// - /// - /// - public static CommandResponse WithMessage(this CommandResponse response, string message) - { - response.Message = message; - return response; - } + /// + /// Set response message and return the current instance. + /// + /// + /// + /// + public static CommandResponse WithMessage(this CommandResponse response, string message) + { + response.Message = message; + return response; + } - /// - /// Set response error and return the current instance. - /// - /// - /// - /// - public static CommandResponse WithStatus(this CommandResponse response, CommandStatus status) - { - response.Status = status; - return response; - } + /// + /// Sets response status to . + /// + /// + /// + /// + public static CommandResponse Success(this CommandResponse response) + { + response.Status = CommandStatus.Succeed; + return response; + } - /// - /// Sets response status to . - /// - /// - /// - /// - public static CommandResponse Success(this CommandResponse response) - { - response.Status = CommandStatus.Succeed; - return response; - } + /// + /// Set response status to . + /// + /// + /// + /// + /// + public static CommandResponse Success(this CommandResponse response, TResult result) + { + return response.Success().WithResult(result); + } - /// - /// Set response status to . - /// - /// - /// - /// - /// - public static CommandResponse Success(this CommandResponse response, TResult result) - { - return response.Success().WithResult(result); - } + /// + /// + /// + /// + /// + /// + /// + public static CommandResponse Failure(this CommandResponse response, Exception exception) + { + //response.Status = GetStatus(exception); + response.Error = exception; + response.Message = exception.Message; + response.Code = exception switch + { + BusinessException e => e.Code, + HttpRequestException e => $"HTTP{e.StatusCode}", + _ => response.Code + }; + response.Status = exception is OperationCanceledException ? CommandStatus.Canceled : CommandStatus.Failure; - /// - /// - /// - /// - /// - /// - /// - public static CommandResponse Failure(this CommandResponse response, Exception exception) - { - //response.Status = GetStatus(exception); - response.Error = exception; - response.Message = exception.Message; - response.Code = exception switch - { - BusinessException e => e.Code, - HttpRequestException e => $"HTTP{e.StatusCode}", - _ => response.Code - }; + return response; + } - return response; - } + /// + /// Sets response code and return the current instance. + /// + /// + /// + /// + /// + public static CommandResponse WithCode(this CommandResponse response, string code) + { + response.Code = code; + return response; + } - /// - /// Sets response code and return the current instance. - /// - /// - /// - /// - /// - public static CommandResponse WithCode(this CommandResponse response, string code) - { - response.Code = code; - return response; - } + /// + /// Sets response message and return the current instance. + /// + /// + /// + /// + /// + public static CommandResponse WithMessage(this CommandResponse response, string message) + { + response.Message = message; + return response; + } - /// - /// Sets response message and return the current instance. - /// - /// - /// - /// - /// - public static CommandResponse WithMessage(this CommandResponse response, string message) - { - response.Message = message; - return response; - } - - /// - /// Sets response result and return the current instance. - /// - /// - /// - /// - /// - public static CommandResponse WithResult(this CommandResponse response, TResult result) - { - response.Result = result; - return response; - } - - /// - /// Sets the response status and return the current instance. - /// - /// - /// - /// - /// - public static CommandResponse WithStatus(this CommandResponse response, CommandStatus status) - { - response.Status = status; - return response; - } + /// + /// Sets response result and return the current instance. + /// + /// + /// + /// + /// + public static CommandResponse WithResult(this CommandResponse response, TResult result) + { + response.Result = result; + return response; + } } \ No newline at end of file diff --git a/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs b/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs index 9ef2f5b..10895cf 100644 --- a/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs +++ b/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs @@ -12,74 +12,75 @@ namespace Nerosoft.Euonia.Hosting; /// public class ExceptionHandlingMiddleware : IMiddleware { - private readonly ILogger _logger; + private readonly ILogger _logger; - /// - /// Initialize a new instance of . - /// - /// - public ExceptionHandlingMiddleware(ILoggerFactory logger) - { - _logger = logger.CreateLogger(); - } + /// + /// Initialize a new instance of . + /// + /// + public ExceptionHandlingMiddleware(ILoggerFactory logger) + { + _logger = logger.CreateLogger(); + } - /// - public async Task InvokeAsync(HttpContext context, RequestDelegate next) - { - try - { - await next(context); - } - catch (Exception exception) - { - _logger.LogError(exception, "{Message}", exception.Message); + /// + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + try + { + await next(context); + } + catch (Exception exception) + { + _logger.LogError(exception, "{Message}", exception.Message); - await HandleExceptionAsync(context, exception); - } - } + await HandleExceptionAsync(context, exception); + } + } - private static async Task HandleExceptionAsync(HttpContext httpContext, Exception exception) - { - var statusCode = GetStatusCode(exception); + private static Task HandleExceptionAsync(HttpContext httpContext, Exception exception) + { + var statusCode = GetStatusCode(exception); - var response = new - { - status = statusCode, - message = exception.Message, - details = GetErrors(exception) - }; + var response = new + { + status = statusCode, + message = exception.Message, + details = GetErrors(exception) + }; - httpContext.Response.ContentType = "application/json"; + httpContext.Response.ContentType = "application/json"; - httpContext.Response.StatusCode = statusCode; + httpContext.Response.StatusCode = statusCode; - await httpContext.Response.WriteAsync(JsonSerializer.Serialize(response)); - } + return httpContext.Response.WriteAsync(JsonSerializer.Serialize(response)); + } - private static int GetStatusCode(Exception exception) - { - return exception switch - { - HttpStatusException ex => (int)ex.StatusCode, - AuthenticationException => StatusCodes.Status401Unauthorized, - UnauthorizedAccessException => StatusCodes.Status403Forbidden, - ValidationException => StatusCodes.Status422UnprocessableEntity, - NotImplementedException => StatusCodes.Status501NotImplemented, - _ => (int)(exception.GetType().GetCustomAttribute()?.StatusCode ?? HttpStatusCode.InternalServerError) - }; - } + private static int GetStatusCode(Exception exception) + { + return exception switch + { + HttpStatusException ex => (int)ex.StatusCode, + AuthenticationException => StatusCodes.Status401Unauthorized, + UnauthorizedAccessException => StatusCodes.Status403Forbidden, + ValidationException => StatusCodes.Status422UnprocessableEntity, + NotImplementedException => StatusCodes.Status501NotImplemented, + AggregateException ex => GetStatusCode(ex.InnerException), + _ => (int)(exception.GetType().GetCustomAttribute()?.StatusCode ?? HttpStatusCode.InternalServerError) + }; + } - private static IReadOnlyDictionary GetErrors(Exception exception) - { - //IReadOnlyDictionary errors = null; + private static IReadOnlyDictionary GetErrors(Exception exception) + { + //IReadOnlyDictionary errors = null; - if (exception is not ValidationException ex) - { - return null; - } + if (exception is not ValidationException ex) + { + return null; + } - return ex.Errors - .GroupBy(t => t.PropertyName) - .ToDictionary(t => t.Key, t => t.Select(x => x.ErrorMessage).ToArray()); - } + return ex.Errors + .GroupBy(t => t.PropertyName) + .ToDictionary(t => t.Key, t => t.Select(x => x.ErrorMessage).ToArray()); + } } \ No newline at end of file diff --git a/Source/Euonia.Repository.EfCore/DataContextBase.cs b/Source/Euonia.Repository.EfCore/DataContextBase.cs index 058dbfd..e6aa531 100644 --- a/Source/Euonia.Repository.EfCore/DataContextBase.cs +++ b/Source/Euonia.Repository.EfCore/DataContextBase.cs @@ -1,9 +1,7 @@ using System.Data; -using System.Diagnostics; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.Logging; using Nerosoft.Euonia.Domain; namespace Nerosoft.Euonia.Repository.EfCore; diff --git a/Tests/Euonia.Bus.Tests.Shared/Commands/FooDeleteCommand.cs b/Tests/Euonia.Bus.Tests.Shared/Commands/FooDeleteCommand.cs new file mode 100644 index 0000000..6d43665 --- /dev/null +++ b/Tests/Euonia.Bus.Tests.Shared/Commands/FooDeleteCommand.cs @@ -0,0 +1,7 @@ +namespace Nerosoft.Euonia.Bus.Tests.Commands; + +[Queue] +public class FooDeleteCommand +{ + +} \ No newline at end of file diff --git a/Tests/Euonia.Bus.Tests.Shared/Euonia.Bus.Tests.Shared.projitems b/Tests/Euonia.Bus.Tests.Shared/Euonia.Bus.Tests.Shared.projitems index 413a03d..f5b0fac 100644 --- a/Tests/Euonia.Bus.Tests.Shared/Euonia.Bus.Tests.Shared.projitems +++ b/Tests/Euonia.Bus.Tests.Shared/Euonia.Bus.Tests.Shared.projitems @@ -10,6 +10,7 @@ + diff --git a/Tests/Euonia.Bus.Tests.Shared/Handlers/FooCommandHandler.cs b/Tests/Euonia.Bus.Tests.Shared/Handlers/FooCommandHandler.cs index 0f684bc..b1300ea 100644 --- a/Tests/Euonia.Bus.Tests.Shared/Handlers/FooCommandHandler.cs +++ b/Tests/Euonia.Bus.Tests.Shared/Handlers/FooCommandHandler.cs @@ -11,4 +11,10 @@ public async Task HandleAsync(FooCreateCommand message, MessageContext messageCo messageContext.Response(1); await Task.CompletedTask; } -} + + [Subscribe] + public async Task HandleAsync(FooDeleteCommand message, MessageContext messageContext, CancellationToken cancellationToken = default) + { + throw new NotFoundException(); + } +} \ No newline at end of file diff --git a/Tests/Euonia.Bus.Tests.Shared/ServiceBusTests.cs b/Tests/Euonia.Bus.Tests.Shared/ServiceBusTests.cs index 2dae183..259d621 100644 --- a/Tests/Euonia.Bus.Tests.Shared/ServiceBusTests.cs +++ b/Tests/Euonia.Bus.Tests.Shared/ServiceBusTests.cs @@ -30,7 +30,7 @@ public async Task TestSendCommand_HasResponse() } [Fact] - public async Task TestSendCommand_NoReponse() + public async Task TestSendCommand_NoResponse() { if (_preventRunTests) { @@ -44,7 +44,7 @@ public async Task TestSendCommand_NoReponse() } [Fact] - public async Task TestSendCommand_HasReponse_UseSubscribeAttribute() + public async Task TestSendCommand_HasResponse_UseSubscribeAttribute() { if (_preventRunTests) { @@ -58,7 +58,7 @@ public async Task TestSendCommand_HasReponse_UseSubscribeAttribute() } [Fact] - public async Task TestSendCommand_HasReponse_MessageHasResultInherites() + public async Task TestSendCommand_HasResponse_MessageHasResultInherits() { if (_preventRunTests) { @@ -72,7 +72,7 @@ public async Task TestSendCommand_HasReponse_MessageHasResultInherites() } [Fact] - public async Task TestSendCommand_HasReponse_MessageHasResultInherites_NoRecipient() + public async Task TestSendCommand_HasResponse_MessageHasResultInherits_NoRecipient() { if (_preventRunTests) { @@ -82,7 +82,23 @@ public async Task TestSendCommand_HasReponse_MessageHasResultInherites_NoRecipie { await Assert.ThrowsAnyAsync(async () => { - var result = await _provider.GetService().SendAsync(new FooCreateCommand()); + var _ = await _provider.GetService().SendAsync(new FooCreateCommand()); + }); + } + } + + [Fact] + public async Task TestSendCommand_HasResponse_MessageHasResultInherits_ThrowExceptionInHandler() + { + if (_preventRunTests) + { + Assert.True(true); + } + else + { + await Assert.ThrowsAnyAsync(async () => + { + await _provider.GetService().SendAsync(new FooDeleteCommand()); }); } } diff --git a/project.props b/project.props index ce3b82f..fdaadce 100644 --- a/project.props +++ b/project.props @@ -1,6 +1,6 @@ - 8.1.4 + 8.1.5 damon Nerosoft Ltd. Euonia