Après avoir créé, structuré et posé les bases Clean Architecture .NET, il est temps de passer à l’APIUne API est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données., pas à pas, c’est parti !
Pour retrouver la 1ère partie de ce tuto, RDV par ici.
On va créer une API qui va nous permettre de récupérer un mot ou une liste de mots :
Pour commencer, nous allons implémenter tous les fichiers relatifs à notre “Mot” :
Mot.cs → Projet Domain, dossier Models
public class Mot : BaseEntity
{
public string Text { get; set; }
}
On va créer les interfaces ainsi que le repository et le service associé :
MotRepository.cs → Projet Infrastructure, dossier RepositoryC'est l'emplacement où Git va stocker toutes les informations permettant de gérer le versioning et l'historisation d'une application.
public class MotRepository : BaseRepository<Mot, CoreDbContext>
{
public MotRepository(CoreDbContext databaseContext) : base(databaseContext)
{
}
}
MotService.cs → Projet ApplicationC'est un programme conçu pour effectuer une ou plusieurs tâches. Réaliser des applications, c'est notre cœur de métier chez AXOPEN !, dossier Service
public class MotService : BaseService<IMotRepository, Mot>
{
public MotService(MotRepository repository) : base(repository)
{
}
}
Avant de pouvoir utiliser nos services fraîchement créés dans nos contrôleurs, nous allons devoir les déclarer pour pouvoir effectuer l’injection de dépendances.
Pour ce faire, nous allons créer un fichier DependencyInjection à la racine du projet Infrastructure ainsi qu’à la racine du projet Applications :
DependencyInjection.cs → Projet Infrastructure
public static class DependencyInjection
{
public static void AddRepositories(this IServiceCollection services)
{
//Ajouter les repository
services.AddScoped<MotRepository>();
}
}
DependencyInjection.cs → Projet Application
public static class DependencyInjection
{
public static void AddServices(this IServiceCollection services)
{
//Ajouter les services
services.AddScoped<MotService>();
}
}
TIPS : Vous allez forcément avoir une application de plus en plus grosse. Dans ce cas, il faut automatiser ces imports :
Voici une fonction qui permet de récupérer tous les fichiers finissant par Repository, dans le namespace Repository de notre projet Infrastructure et d’automatiquement signaler à notre API de les enregistrer :
public static void AddRepositories(this IServiceCollection services)
{
Assembly assembly = Assembly.GetExecutingAssembly();
assembly.GetTypes().Where(t => $"{assembly.GetName().Name}.Repository" == t.Namespace
&& !t.IsAbstract
&& !t.IsInterface
&& t.Name.EndsWith("Repository"))
.Select(a => new { assignedType = a, serviceTypes = a.GetInterfaces().ToList() })
.ToList()
.ForEach(typesToRegister =>
{
typesToRegister.serviceTypes.ForEach(typeToRegister => services.AddScoped(typeToRegister, typesToRegister.assignedType));
});
}
Pour la partie Services, il suffit de remplacer “Repository” par “Service” et vous aurez vos injections automatiques !
Après pour faire encore plus proprement, on peut passer par un “Attribute”, récupérer tous les types qui ont cette annotation et les injecter.
Grâce à ces fichiers, on va pouvoir déclarer tous nos repository et services en une seule ligne de code :
→ .NET 6 : dans le fichier Program.cs juste après l’initialisation du builder :
// Add services to the container.
builder.Services.AddServices();
builder.Services.AddRepositories();
→ .NET 5 et inférieur, cela se situe dans le fichier Startup.cs, dans la méthode ConfigureServices(IServiceCollection services) dans laquelle on va pouvoir rajouter :
services.AddServices();
services.AddRepositories();
On rajoute le modèle créé à notre dbContext :
public class CoreDbContext : DbContext
{
public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options)
{ }
public DbSet<Mot> Mot { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
Ici, on va créer un dossier EntityConfigurations dans le Projet Infrastructure et dans le dossier Database :
MotConfiguration.cs → Projet Infrastructure, dossier Database puis EntityConfigurations
public class MotConfiguration : IEntityTypeConfiguration<Mot>
{
public void Configure(EntityTypeBuilder<Mot> builder)
{
builder.ToTable(nameof(Mot));
builder.HasKey(c => c.Id).HasAnnotation("DatabaseGenerated", DatabaseGeneratedOption.Identity);
}
}
Cela va permettre à EF de créer correctement notre modèle lors de notre première migration.
Il ne faut pas oublier de lui signaler ce fichier :
public class CoreDbContext : DbContext
{
public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options)
{ }
public DbSet<Mot> Mot { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
ApplyConfigurationsFromAssembly est une méthode du ModelBuilder, qui va nous permettre d’appliquer automatiquement toutes les configurations à l’intérieur de notre assembly, ici le projet Infrastructure.
Finalisons la création de notre API !
MotController.cs → Projet API, dossier Controller
public class MotController : ControllerBase
{
IMotService _motService;
public MotController(IMotService motService)
{
_motService = motService;
}
[HttpGet]
public async Task<ActionResult> GetAll()
{
try
{
ActionResult result = StatusCode(500);
List<Mot> mots = await _motService.GetAllAsync();
if(mots.IsNotEmpty())
{
result = Ok(mots);
}
return result;
}
catch (Exception e)
{
return StatusCode(500, e.StackTrace);
}
}
[HttpGet]
[Route("{id}")]
public async Task<ActionResult> GetById()
{
try
{
ActionResult result = StatusCode(500);
Mot mot = await _motService.GetById(1);
if (mot != null)
{
result = Ok(mot);
}
return result;
}
catch (Exception e)
{
return StatusCode(500, e.StackTrace);
}
}
}
J’ai créé une extension pour les listes pour implémenter la méthode isNotEmpty() :
ListExtensions.cs → Projet Helpers, dossier Extensions
public static class ListExtensions
{
public static bool IsNotEmpty<T>(this IList<T> list)
{
return list != null && list.Count > 0;
}
}
Et voilà !
Il vous suffit d’initialiser votre base de données et de créer la première migration afin de faire fonctionner votre API !
Tuto : Vous souhaitez mettre en place une architecture propre et maintenable sur votre API .NET Core ? Vous êtes au bon endroit ! À la fin de cet article, vous aurez une API REST avec une architecture clean
Comprendre comment gérer correctement les exceptions est essentiel pour garantir la robustesse de vos applications. Cet article explore les principes fondamentaux de la gestion des exceptions en .NET et vous montre une façon de tout centraliser.
Tuto - Talend – Appeler et exposer un web service rest