diff --git a/BlazorApp/BlazorApp.csproj b/BlazorApp/BlazorApp.csproj index c0efc44..6b090a1 100644 --- a/BlazorApp/BlazorApp.csproj +++ b/BlazorApp/BlazorApp.csproj @@ -21,6 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/BlazorApp/Middlewares/ErrorHandlingMiddleware.cs b/BlazorApp/Middlewares/ErrorHandlingMiddleware.cs new file mode 100644 index 0000000..f1f783f --- /dev/null +++ b/BlazorApp/Middlewares/ErrorHandlingMiddleware.cs @@ -0,0 +1,71 @@ +using System.Net; +using BlazorApp.Models.Exceptions; +using Newtonsoft.Json; + +namespace BlazorApp.Middlewares +{ + public class ErrorHandlingMiddleware + { + private readonly RequestDelegate next; + private readonly ILogger _logger; + + public ErrorHandlingMiddleware( + RequestDelegate next, + ILogger logger) + { + this.next = next; + this._logger = logger; + } + + public async Task Invoke(HttpContext context) + { + try + { + await next(context); + } + catch (System.Exception ex) + { + await this.HandleAsync(context, ex); + } + } + + private async Task HandleAsync(HttpContext context, System.Exception exception) + { + HandledException handled = this.HandleException(exception); + + this._logger.LogError(exception, $"returning code {handled.StatusCode} and payload {handled.Message}"); + + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)handled.StatusCode; + await context.Response.WriteAsync(handled.Message); + } + + protected HandledException HandleException(System.Exception exception) + { + HttpStatusCode statusCode; + + if (exception is NotFoundException) + { + statusCode = HttpStatusCode.NotFound; + } + else if (exception is ValidationException) + { + statusCode = HttpStatusCode.BadRequest; + } + else if (exception is BusinessException) + { + statusCode = HttpStatusCode.InternalServerError; + } + else + { + statusCode = HttpStatusCode.InternalServerError; + } + + return new HandledException() + { + StatusCode = statusCode, + Message = JsonConvert.SerializeObject(new { error = exception.Message }) + }; + } + } +} diff --git a/BlazorApp/Models/Exceptions/BusinessException.cs b/BlazorApp/Models/Exceptions/BusinessException.cs new file mode 100644 index 0000000..7d2fd57 --- /dev/null +++ b/BlazorApp/Models/Exceptions/BusinessException.cs @@ -0,0 +1,9 @@ +namespace BlazorApp.Models.Exceptions +{ + public class BusinessException : System.Exception + { + public BusinessException() : base() { } + public BusinessException(String message) : base(message) { } + public BusinessException(String message, System.Exception innerException) : base(message, innerException) { } + } +} diff --git a/BlazorApp/Models/Exceptions/HandledException.cs b/BlazorApp/Models/Exceptions/HandledException.cs new file mode 100644 index 0000000..b0cba1c --- /dev/null +++ b/BlazorApp/Models/Exceptions/HandledException.cs @@ -0,0 +1,10 @@ +using System.Net; + +namespace BlazorApp.Models.Exceptions +{ + public class HandledException + { + public HttpStatusCode StatusCode { get; set; } + public string Message { get; set; } + } +} diff --git a/BlazorApp/Models/Exceptions/NotFoundException.cs b/BlazorApp/Models/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..7373b2f --- /dev/null +++ b/BlazorApp/Models/Exceptions/NotFoundException.cs @@ -0,0 +1,9 @@ +namespace BlazorApp.Models.Exceptions +{ + public class NotFoundException : System.Exception + { + public NotFoundException() : base() { } + public NotFoundException(String message) : base(message) { } + public NotFoundException(String message, System.Exception innerException) : base(message, innerException) { } + } +} diff --git a/BlazorApp/Models/Exceptions/ValidationException.cs b/BlazorApp/Models/Exceptions/ValidationException.cs new file mode 100644 index 0000000..ddbf7b9 --- /dev/null +++ b/BlazorApp/Models/Exceptions/ValidationException.cs @@ -0,0 +1,9 @@ +namespace BlazorApp.Models.Exceptions +{ + public class ValidationException : System.Exception + { + public ValidationException() : base() { } + public ValidationException(String message) : base(message) { } + public ValidationException(String message, System.Exception innerException) : base(message, innerException) { } + } +} diff --git a/BlazorApp/Program.cs b/BlazorApp/Program.cs index b436c9d..250f93f 100644 --- a/BlazorApp/Program.cs +++ b/BlazorApp/Program.cs @@ -4,6 +4,7 @@ using BlazorApp.Components; using BlazorApp.Data.Context; using BlazorApp.Interfaces.Repositories; using BlazorApp.Interfaces.Services; +using BlazorApp.Middlewares; using BlazorApp.Models.Config; using BlazorApp.Repositories.Database; using BlazorApp.Repositories.InMemory; @@ -40,6 +41,7 @@ builder.Services.AddClientServices(); var app = builder.Build(); +app.UseMiddleware(typeof(ErrorHandlingMiddleware)); app.ExecuteDbMigration(); if (app.Environment.IsDevelopment()) diff --git a/BlazorApp/Repositories/Database/CustomerDatabaseRepository.cs b/BlazorApp/Repositories/Database/CustomerDatabaseRepository.cs index 00a2a22..ceb9e41 100644 --- a/BlazorApp/Repositories/Database/CustomerDatabaseRepository.cs +++ b/BlazorApp/Repositories/Database/CustomerDatabaseRepository.cs @@ -1,9 +1,9 @@ using BlazorApp.Data; using BlazorApp.Data.Context; using BlazorApp.Interfaces.Repositories; +using BlazorApp.Models.Exceptions; using BlazorApp.Shared.Queries; using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations; namespace BlazorApp.Repositories.Database { @@ -27,7 +27,7 @@ namespace BlazorApp.Repositories.Database Customer data = await this._dbContext.Customers.FindAsync(id); if (data is null) { - throw new KeyNotFoundException($"Customer with id: {id} not found"); + throw new NotFoundException($"Customer with id: {id} not found"); } return data; } diff --git a/BlazorApp/Services/BaseService.cs b/BlazorApp/Services/BaseService.cs new file mode 100644 index 0000000..beba1a4 --- /dev/null +++ b/BlazorApp/Services/BaseService.cs @@ -0,0 +1,11 @@ +namespace BlazorApp.Services +{ + public class BaseService + { + protected readonly ILogger _logger; + public BaseService(ILogger logger) + { + this._logger = logger; + } + } +} diff --git a/BlazorApp/Services/CustomerService.cs b/BlazorApp/Services/CustomerService.cs index 3e2a650..ca9b8da 100644 --- a/BlazorApp/Services/CustomerService.cs +++ b/BlazorApp/Services/CustomerService.cs @@ -1,32 +1,38 @@ using BlazorApp.Interfaces.Repositories; using BlazorApp.Interfaces.Services; +using BlazorApp.Models.Exceptions; using BlazorApp.Shared.Models; using BlazorApp.Shared.Models.Pagination; using BlazorApp.Shared.Queries; namespace BlazorApp.Services { - public class CustomerService : ICustomerService + public class CustomerService : BaseService, ICustomerService { private readonly ICustomerRepository _customerRepository; - public CustomerService(ICustomerRepository customerRepository) + public CustomerService(ICustomerRepository customerRepository, ILogger logger) : base(logger) { this._customerRepository = customerRepository; } public async Task Delete(string id) { + this._logger.LogInformation($"Gonna delete customer with id: {id}"); await this._customerRepository.Delete(id); + this._logger.LogInformation($"Deleted customer with id: {id}"); } public async Task Get(string id) { + this._logger.LogInformation($"Gonna get customer with id: {id}"); Data.Customer data = await this._customerRepository.Get(id); + this._logger.LogInformation($"Got customer with id: {id}"); return data.Convert(); } public async Task> Query(CustomerQuery query) { + this._logger.LogInformation($"Querying customers"); IEnumerable datas = await this._customerRepository.Query(query); return new PaginatedResult() { @@ -37,12 +43,16 @@ namespace BlazorApp.Services public async Task Save(Customer customer) { + this._logger.LogInformation($"Gonna save new customer"); await this._customerRepository.Save(customer); + this._logger.LogInformation($"New customer saved successfully"); } public async Task Update(Customer customer) { + this._logger.LogInformation($"Gonna update customer with id: {customer.Id}"); await this._customerRepository.Update(customer); + this._logger.LogInformation($"Customer with id: {customer.Id} updated successfully"); } public async Task Count() => await this._customerRepository.Count(); diff --git a/BlazorApp/appsettings.Development.json b/BlazorApp/appsettings.Development.json index e590b7d..e420810 100644 --- a/BlazorApp/appsettings.Development.json +++ b/BlazorApp/appsettings.Development.json @@ -14,6 +14,6 @@ "CustomerCacheKey": "customer", "CustomerCacheSeconds": 5 }, - "MockCustomers": true, + "MockCustomers": false, "MockCustomersCount": 238 }