Vous pouvez trouver le code source complet sur github
Conditions préalables
- Code Visual Studio / Visual Studio
- SDK .NET Core 6
- Compréhension de la programmation C#
- Compréhension des API .NET Core
Introduction
Lorsque nous construisons notre application, bien que nous espérons que notre application fonctionnera sans aucune erreur jusqu’à la fin des temps. Ce n’est pas vraiment le cas, des exceptions se produisent dans les applications et nous devons les gérer.
La gestion des exceptions est une base que nous devons prendre en compte lors de la conception et de la construction de notre application pour avoir une application stable et éviter les pannes d’application.
Il existe de nombreuses façons d’implémenter la gestion des exceptions lors de la construction de nos applications à partir d’une approche très granulaire vers une approche plus générique.
Dans cet article, nous explorerons la gestion globale des exceptions via le middleware pour détecter efficacement les erreurs d’exécution conformément à nos exigences.
Code
La première chose que nous devons faire est de créer une nouvelle application WebApi
dotnet new webapi -n ErrorManagement
Maintenant que notre application a été créée, nous devons installer certains packages
dotnet add package Microsoft.EntityFrameworkCore dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL dotnet add package Microsoft.EntityFrameworkCore.Tools
Pour nous assurer que tout fonctionne comme il se doit, nous devons créer notre application
dotnet build
Il est maintenant temps d’ajouter les modèles, pour cet exemple d’application, nous allons créer une application pour répertorier tous les pilotes F1. Pour cela nous allons créer un dossier Models dans le répertoire racine de notre application qui contiendra nos modèles Dans le dossier Models, nous allons créer une nouvelle classe appelée Employee
namespace Net.WebApi.Globalexcpetions.Models; public class Employee { public int Id { get; set; } public string FirstName { get; set; } = ""; public string LastName { get; set; } = ""; }
Une fois le modèle créé, l’étape suivante consiste à créer notre contexte de base de données dans le répertoire racine de notre application. Nous allons créer un nouveau dossier appelé Data et à l’intérieur du dossier Data, nous ajouterons la classe ApiDbContext.
using Microsoft.EntityFrameworkCore; using Net.WebApi.Globalexcpetions.Models; namespace Net.WebApi.Globalexcpetions.Data; public class ApiDbContext :DbContext { public ApiDbContext(DbContextOptions<ApiDbContext> options) : base(options) { } public DbSet<Employee> Employees { get; set; } }
Maintenant, nous devons ajouter la chaîne de connexion dans le appsettings.json
"ConnectionStrings": { "SampleDbConnection": "User ID =mohamad;Password=12345678;Server=localhost;Port=5432;Database=sampledb; Integrated Security=true;Pooling=true;" }
Ensuite, nous devons mettre à jour notre program.cs
builder.Services.AddEntityFrameworkNpgsql().AddDbContext<ApiDbContext>(opt => opt.UseNpgsql(builder.Configuration.GetConnectionString("SampleDbConnection")));
Une fois que nous les ajoutons, nous pouvons faire notre migration
dotnet ef migrations add "initial_migration" dotnet ef database update
Créons maintenant les EmployeeServices dans le répertoire racine de notre application, créons un nouveau dossier appelé Services et dans ce dossier, nous allons créer une nouvelle interface appelée IEmployeeService
using Net.WebApi.Globalexcpetions.Models; namespace Net.WebApi.Globalexcpetions.Services; public interface IEmployeeService { public Task<IEnumerable<Employee>> GetEmployees(); public Task<Employee?> GetEmployeeById(int id); public Task<Employee> AddEmployee(Employee Employee); public Task<Employee> UpdateEmployee(Employee Employee); public Task<bool> DeleteEmployee(int Id); }
Maintenant, dans le même dossier, nous allons créer une nouvelle classe appelée EmployeeService
using Microsoft.EntityFrameworkCore; using Net.WebApi.Globalexcpetions.Data; using Net.WebApi.Globalexcpetions.Models; namespace Net.WebApi.Globalexcpetions.Services; public class EmployeeService : IEmployeeService { private readonly ApiDbContext _dbContext; public EmployeeService(ApiDbContext dbContext) { _dbContext = dbContext; } public async Task<IEnumerable<Employee>> GetEmployees() { return await _dbContext.Employees.ToListAsync(); } public async Task<Employee?> GetEmployeeById(int id) { return await _dbContext.Employees.FirstOrDefaultAsync(x => x.Id == id); } public async Task<Employee> AddEmployee(Employee Employee) { var result = _dbContext.Employees.Add(Employee); await _dbContext.SaveChangesAsync(); return result.Entity; } public async Task<Employee> UpdateEmployee(Employee Employee) { var result = _dbContext.Employees.Update(Employee); await _dbContext.SaveChangesAsync(); return result.Entity; } public async Task<bool> DeleteEmployee(int Id) { var filteredData = _dbContext.Employees.FirstOrDefault(x => x.Id == Id); var result = _dbContext.Remove(filteredData); await _dbContext.SaveChangesAsync(); return result != null ? true : false; } }
Mettons maintenant à jour notre Program.cs afin que nos EmployeeServices soient injectés dans notre conteneur Dependency Inject
builder.Services.AddScoped<IEmployeeService, EmployeeService>();
Maintenant, créons notre EmployessController, à l’intérieur du dossier du contrôleur, nous allons créer une nouvelle classe appelée EmployessController et ajouterons ce qui suit
using Microsoft.AspNetCore.Mvc; using Net.WebApi.Globalexcpetions.Models; using Net.WebApi.Globalexcpetions.Services; namespace Net.WebApi.Globalexcpetions.Controllers; [ApiController] [Route("[controller]")] public class EmployeesController : ControllerBase { private readonly ILogger<EmployeesController> _logger; private readonly IEmployeeService _employeeServices; public EmployeesController( ILogger<EmployeesController> logger, IEmployeeService employeeServices) { _logger = logger; _employeeServices = employeeServices; } [HttpGet("employeelist")] public async Task<IEnumerable<Employee>> employeeList() { var employeeList = await _employeeServices.GetEmployees(); return employeeList; } [HttpGet("getemployeebyid")] public async Task<IActionResult> GetemployeeById(int Id) { _logger.LogInformation($"Fetch employee with ID: {Id} from the database"); var employee = await _employeeServices.GetEmployeeById(Id); if (employee == null) { //throw new Notfound($"employee ID {Id} not found."); return NotFound(); } _logger.LogInformation($"Returning employee with ID: {employee.Id}."); return Ok(employee); } [HttpPost("addemployee")] public async Task<IActionResult> Addemployee(Employee employee) { var result = await _employeeServices.AddEmployee(employee); return Ok(result); } [HttpPut("updateemployee")] public async Task<IActionResult> Updateemployee(Employee employee) { var result = await _employeeServices.UpdateEmployee(employee); return Ok(result); } [HttpDelete("deleteemployee")] public async Task<bool> Deleteemployee(int Id) { return await _employeeServices.DeleteEmployee(Id); } }
Ajoutons maintenant un nouveau dossier appelé Exceptions qui sera utilisé pour gérer toutes nos exceptions
Nous ajouterons les exceptions suivantes
namespace Net.WebApi.Globalexcpetions.Exceptions; public class BadRequestException : Exception { public BadRequestException(string message) : base(message) { } }
namespace Net.WebApi.Globalexcpetions.Exceptions; public class KeyNotFoundException : Exception { public KeyNotFoundException(string message) : base(message) { } }
namespace Net.WebApi.Globalexcpetions.Exceptions; public class NotFoundException : Exception { public NotFoundException(string message) : base(message) { } }
namespace Net.WebApi.Globalexcpetions.Exceptions; public class NotImplementedException : Exception { public NotImplementedException(string message) : base(message) { } }
namespace Net.WebApi.Globalexcpetions.Exceptions; public class UnauthorizedAccessException : Exception { public UnauthorizedAccessException(string message) : base(message) { } }
Maintenant que nos exceptions ont été ajoutées, nous devons ajouter un dossier au répertoire racine de notre application appelé configurations où nous pouvons construire notre GlobalErrorHandlingMiddleware
using System.Net; using System.Text.Json; using Net.WebApi.Globalexcpetions.Exceptions; using KeyNotFoundException = Net.WebApi.Globalexcpetions.Exceptions.KeyNotFoundException; using NotImplementedException = Net.WebApi.Globalexcpetions.Exceptions.NotImplementedException; using UnauthorizedAccessException = Net.WebApi.Globalexcpetions.Exceptions.UnauthorizedAccessException; namespace Net.WebApi.Globalexcpetions.Exceptions; public class GlobalErrorHandlingMiddleware { private readonly RequestDelegate _next; public GlobalErrorHandlingMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); } } private static Task HandleExceptionAsync(HttpContext context, Exception exception) { HttpStatusCode status; var stackTrace = string.Empty; string message; var exceptionType = exception.GetType(); if (exceptionType == typeof(BadRequestException)) { message = exception.Message; status = HttpStatusCode.BadRequest; stackTrace = exception.StackTrace; } else if (exceptionType == typeof(NotFoundException)) { message = exception.Message; status = HttpStatusCode.NotFound; stackTrace = exception.StackTrace; } else if (exceptionType == typeof(NotImplementedException)) { status = HttpStatusCode.NotImplemented; message = exception.Message; stackTrace = exception.StackTrace; } else if (exceptionType == typeof(UnauthorizedAccessException)) { status = HttpStatusCode.Unauthorized; message = exception.Message; stackTrace = exception.StackTrace; } else if (exceptionType == typeof(KeyNotFoundException)) { status = HttpStatusCode.Unauthorized; message = exception.Message; stackTrace = exception.StackTrace; } else { status = HttpStatusCode.InternalServerError; message = exception.Message; stackTrace = exception.StackTrace; } var exceptionResult = JsonSerializer.Serialize(new { error = message, stackTrace }); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)status; return context.Response.WriteAsync(exceptionResult); } }
Le GlobalErrorHandlingMiddleware est utilisé pour fournir plus de contrôle sur les exceptions que l’application va générer
S’il y a des erreurs dans une demande entrante, le GlobalErrorHandlingMiddleware traitera l’erreur
Créons maintenant ApplicationBuilderExtension afin que nous puissions injecter notre middleware dans le dossier Services
using Net.WebApi.Globalexcpetions.Exceptions; namespace Net.WebApi.Globalexcpetions.Configurations; public static class ApplicationBuilderExtensions { public static IApplicationBuilder AddGlobalErrorHandler(this IApplicationBuilder applicationBuilder) => applicationBuilder.UseMiddleware<GlobalErrorHandlingMiddleware>(); }
Injectons maintenant ceci dans le Program.cs
app.AddGlobalErrorHandler();
Veuillez fournir vos commentaires et poser toute question.
Derniers Articles
- Hangfire avec ASP.NET Core
- Premiers pas avec AutoMapper dans ASP.NET Core
- Serilog dans ASP.NET Core 3.1-La journalisation structurée simplifiée
Vous aimez le contenu ?
Si vous aimez mes articles, pensez à m’acheter quelques cafés !