Fermer

janvier 8, 2025

Création d’une API complète avec Visual Studio Scaffolding

Création d’une API complète avec Visual Studio Scaffolding


Créer une API à partir de zéro peut être un processus laborieux et sujet aux erreurs, notamment en raison d’erreurs de syntaxe ou même de fautes de frappe. Cependant, Visual Studio propose une fonctionnalité qui facilite ce processus, permettant ainsi de gagner du temps et d’éviter les complications. Consultez cet article pour savoir comment utiliser les fonctionnalités d’échafaudage de Visual Studio pour créer une API complète.

Les API Web sont devenues un concept fondamental dans les applications Web modernes, grâce à leur polyvalence et leur simplicité. Malgré les ajouts récents à ASP.NET Core, tels que les API minimales, du code supplémentaire est toujours requis, en particulier lors de l’utilisation de l’approche code-first avec Entity Framework Core. Dans cette approche, des configurations incorrectes peuvent générer des erreurs qui ralentissent souvent le développement.

Pour faciliter ce processus, il existe des fonctionnalités telles que la technique de l’échafaudage. Dans cet article, nous utiliserons Visual Studio pour créer une API CRUD complète en utilisant les principales fonctions disponibles dans l’échafaudage, telles que la génération d’une classe de contexte et la configuration d’une chaîne de connexion, entre autres.

Qu’est-ce qu’un échafaudage ?

L’échafaudage dans le contexte de la technologie est un concept qui fait référence à une approche ou à un outil utilisé pour accélérer le développement de logiciels en fournissant une structure ou un squelette de base pour le code ou le système.

Le terme fait référence à un « échafaudage », une structure temporaire couramment utilisée dans la construction de bâtiments pour fournir un soutien pendant la construction. De même, dans le contexte technologique, l’échafaudage fournit un support lors du développement de logiciels, facilitant la création de parties de logiciels complexes ou exigeantes en main-d’œuvre qui seraient autrement réalisées manuellement.

Échafaudage dans ASP.NET Core

Dans ASP.NET Core, le concept d’échafaudage est présent à travers des outils qui automatisent la création du code de base nécessaire à la mise en œuvre des fonctionnalités courantes des applications Web, telles que l’interface utilisateur (UI), les opérations de base de données, les modèles d’application et autres.

Dans cet article, nous explorerons certaines des dernières fonctionnalités d’échafaudage fournies par Visual Studio pour créer une API Web complète, avec des opérations CRUD de base (Créer, Lire, Mettre à jour et Supprimer) et une intégration avec une base de données SQL Server. De plus, nous explorerons l’intégration avec Entity Framework Core pour automatiser la création de classes, bases de données et tables utilisées dans l’application.

Avantages de l’utilisation d’échafaudages

L’échafaudage peut être utile dans plusieurs scénarios de développement dans ASP.NET Core, en particulier lorsque l’agilité et la cohérence sont nécessaires. Vous trouverez ci-dessous quelques scénarios dans lesquels cela est recommandé.

  • Générer automatiquement du code : Les fonctionnalités d’échafaudage vous permettent de générer du code automatiquement, ce qui minimise les risques de fautes de frappe et d’autres problèmes pouvant survenir lors de l’écriture manuelle du code.
  • Accélérer le développement : L’échafaudage fournit une base prête à l’emploi pour les opérations CRUD, laissant le développeur libre de se concentrer sur des fonctionnalités plus complexes. Certains scénarios dans lesquels l’échafaudage peut être utile incluent des entretiens techniques où le temps est généralement réduit, des projets initiaux nécessitant un produit minimum viable (MVP) et des projets plus petits pour lesquels il n’y a pas besoin de beaucoup de personnalisation. Pour ces types de scénarios, l’échafaudage peut être utilisé pour configurer rapidement les interactions avec la base de données.
  • Normalisation des codes : Le code généré par l’échafaudage suit les normes ASP.NET Core prédéfinies, ce qui permet de maintenir la cohérence du projet. Ceci est particulièrement utile dans les grandes équipes où l’uniformité du code est importante.
  • Intégration d’Entity Framework : Scaffolding s’intègre à Entity Framework Core, permettant la génération de code à partir de modèles de données ou la création et l’exécution de scripts de base de données.

Conditions préalables

Pour reproduire l’exemple présenté dans l’article, vous devez avoir installé la dernière version de .NET. Au moment de la création du message, la dernière version stable était .NET 8.

De plus, vous devez disposer des dernières versions de Visual Studio. La publication utilise Visual Studio 2022 version 17.11.2.

Cet exemple utilise la base de données SQL Server, vous devez donc disposer d’une connexion locale à SQL Server. Vous pouvez utiliser une autre base de données si vous le jugez nécessaire.

Vous pouvez accéder au code source du projet créé dans la publication dans ce référentiel GitHub : InventaireHub.

Création de l’application

Pour démontrer les fonctions d’échafaudage, nous créerons une API Web pour enregistrer les produits dans un inventaire.

Pour créer l’application de base, ouvrez Visual Studio et cliquez sur « Créer un nouveau projet », puis choisissez l’option « API Web ASP.NET Core ». Donnez un nom au projet (dans l’exemple, nous avons utilisé « InventoryHub »). Dans la fenêtre suivante, sélectionnez la version .NET la plus récente (dans ce cas, 8) et laissez uniquement ces options sélectionnées : Configurer pour HTTPS et Activer la prise en charge OpenAPI. Et puis cliquez sur « Créer ».

Création de l'application

Ensuite, ouvrez le projet avec Visual Studio et, à l’intérieur du projet, créez un nouveau dossier appelé « Entités ». À l’intérieur, créez la classe ci-dessous :

namespace InventoryHub.Entities;
public class ProductItem
{
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public int QuantityInStock { get; set; }
        public string SKU { get; set; }

        public string Category { get; set; }
        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
        public bool IsActive { get; set; } = true;
}

Ici, nous créons une classe simple pour représenter un élément de produit avec uniquement des propriétés, telles que les fonctions de post-focus et d’échafaudage ; des exemples approfondis de classes et de fonctions ne seront pas utilisés.

Création des éléments d’échafaudage

Le ProductItem la classe créée précédemment est la seule classe créée manuellement ; tout le reste sera fait avec les fonctions d’échafaudage présentes dans Visual Studio.

Alors, faites un clic droit sur le projet et recherchez l’option Add > New Scaffolded Item....

Dans la fenêtre qui s’ouvre, cliquez sur le menu de gauche « API » et sélectionnez l’option « API avec points de terminaison en lecture/écriture, utilisant Entity Framework ». Enfin, cliquez sur « Ajouter ».

Création d'un élément échafaudé

Dans la fenêtre suivante, vous devez configurer les classes principales et les points de terminaison EF. Ainsi, dans l’option « Classe modèle », sélectionnez le ProductItem classe.

Dans l’option Classe Endpoint, cliquez sur l’icône « + » (plus) et cliquez sur Ajouter.

Dans l’option de classe DbContext, cliquez sur l’icône « + » (plus) et cliquez sur Ajouter.

Dans l’option Fournisseur de base de données, sélectionnez SQL Server (ou une autre base de données que vous souhaitez utiliser)

Les autres options peuvent conserver la valeur par défaut. Enfin, cliquez sur « Ajouter ».

Ajout d'un élément d'échafaudage

A noter que deux nouvelles classes ont été créées. L’une est la classe « InventoryHubContext », qui se trouve dans le dossier « Data ». Et l’autre est la classe « ProductItemEndpoints ».

Analysons chacun d’eux.

Classe DbContext

La classe « InventoryHubContext » générée dans le dossier « Data » contient les configurations EF Core.

namespace InventoryHub.Data
{
public class InventoryHubContext : DbContext
{
public InventoryHubContext (DbContextOptions<InventoryHubContext> options)
: base(options)
{
}

public DbSet<InventoryHub.Entities.ProductItem> ProductItem { get; set; } = default!;
}
}

La classe hérite de DbContext. Cela signifie qu’il a accès aux méthodes et propriétés de DbContextlui permettant d’interagir avec la base de données en effectuant des opérations CRUD.

Le constructeur reçoit un paramètre options de type DbContextOptions<InventoryHubContext>qui contient des options de configuration pour le contexte de la base de données (telles que la chaîne de connexion). Il transmet ces options au constructeur de la classe de base (DbContext) en utilisant : base(options).

ProductItem représente une collection d’entités dans le contexte qui peuvent être interrogées et enregistrées dans la base de données.

Ici, ProductItem est une propriété de type DbSet<ProductItem>ce qui indique qu’il gérera les instances du ProductItem entité. Le = default!; La syntaxe est utilisée pour supprimer les avertissements nuls, indiquant que cette propriété sera correctement initialisée au moment de l’exécution.

ProductItemEndpoints

Une autre classe générée dans l’échafaudage était la ProductItemEndpoints classe:

public static class ProductItemEndpoints
{
    public static void MapProductItemEndpoints (this IEndpointRouteBuilder routes)
    {
        var group = routes.MapGroup("/api/ProductItem").WithTags(nameof(ProductItem));

        group.MapGet("https://www.telerik.com/", async (InventoryHubContext db) =>
        {
            return await db.ProductItem.ToListAsync();
        })
        .WithName("GetAllProductItems")
        .WithOpenApi();

        group.MapGet("/{id}", async Task<Results<Ok<ProductItem>, NotFound>> (Guid id, InventoryHubContext db) =>
        {
            return await db.ProductItem.AsNoTracking()
                .FirstOrDefaultAsync(model => model.Id == id)
                is ProductItem model
                    ? TypedResults.Ok(model)
                    : TypedResults.NotFound();
        })
        .WithName("GetProductItemById")
        .WithOpenApi();

        group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (Guid id, ProductItem productItem, InventoryHubContext db) =>
        {
            var affected = await db.ProductItem
                .Where(model => model.Id == id)
                .ExecuteUpdateAsync(setters => setters
                    .SetProperty(m => m.Id, productItem.Id)
                    .SetProperty(m => m.Name, productItem.Name)
                    .SetProperty(m => m.Description, productItem.Description)
                    .SetProperty(m => m.Price, productItem.Price)
                    .SetProperty(m => m.QuantityInStock, productItem.QuantityInStock)
                    .SetProperty(m => m.SKU, productItem.SKU)
                    .SetProperty(m => m.Category, productItem.Category)
                    .SetProperty(m => m.CreatedAt, productItem.CreatedAt)
                    .SetProperty(m => m.IsActive, productItem.IsActive)
                    );
            return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
        })
        .WithName("UpdateProductItem")
        .WithOpenApi();

        group.MapPost("https://www.telerik.com/", async (ProductItem productItem, InventoryHubContext db) =>
        {
            db.ProductItem.Add(productItem);
            await db.SaveChangesAsync();
            return TypedResults.Created($"/api/ProductItem/{productItem.Id}",productItem);
        })
        .WithName("CreateProductItem")
        .WithOpenApi();

        group.MapDelete("/{id}", async Task<Results<Ok, NotFound>> (Guid id, InventoryHubContext db) =>
        {
            var affected = await db.ProductItem
                .Where(model => model.Id == id)
                .ExecuteDeleteAsync();
            return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
        })
        .WithName("DeleteProductItem")
        .WithOpenApi();
    }
}

Cette classe est utilisée pour organiser les points de terminaison, évitant ainsi leur dispersion dans la classe Program. Il contient tous les points de terminaison requis pour les opérations CRUD (Créer, Lire, Mettre à jour et Supprimer). De plus, les points de terminaison incluent des fonctionnalités avancées, telles que les « Groupes de routes », qui vous permettent de regrouper efficacement les points de terminaison.

Une autre caractéristique importante est la AsNoTracking() méthode, qui empêche le mappage des modifications aux entités par Entity Framework Core, ce qui entraîne un gain de performances.

Classe de programme

La classe Program contient déjà les configurations nécessaires créées par l’échafaudage :

using Microsoft.EntityFrameworkCore;
using InventoryHub.Data;
using InventoryHub;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<InventoryHubContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("InventoryHubContext") ?? throw new InvalidOperationException("Connection string 'InventoryHubContext' not found.")));

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapProductItemEndpoints();

app.Run();

Ici, le InventoryHubContext les paramètres de classe ont été créés, en lui transmettant la chaîne de connexion qui porte le même nom que la classe. Si la chaîne de connexion n’est pas trouvée, une exception est levée.

En plus des paramètres Swagger, le MapProductItemEndpoints(); est également utilisée, qui est responsable du mappage des points de terminaison de l’API.

Si vous ouvrez le fichier appsettings.json, vous remarquerez peut-être que la chaîne de connexion créée par l’échafaudage est présente :

"ConnectionStrings": {
"InventoryHubContext": "Server=(localdb)\\mssqllocaldb;Database=InventoryHubContext-59891a8e-5733-47b5-8e27-26982d11988a;Trusted_Connection=True;MultipleActiveResultSets=true"
}

Notez que le nom de la base de données possède un GUID (Globally Unique Identifier) ​​pour vérifier qu’une base de données portant ce nom n’existe pas déjà.

Création et exécution de migrations EF Core

La fonctionnalité de migration d’EF Core est utilisée pour générer des scripts de base de données et les exécuter, créant automatiquement des bases de données et des tables basées sur les entités de l’application. Pour ce faire via un échafaudage, suivez les étapes ci-dessous :

  1. Dans Visual Studio, double-cliquez sur l’option Services connectés.

  2. Dans la fenêtre qui s’ouvre, dans le coin droit, dans la deuxième option, cliquez sur les trois points puis sélectionnez l’option « Ajouter une migration » comme indiqué dans l’image ci-dessous :

Ajout de la migration 1

  1. Dans la fenêtre qui s’ouvre, sélectionnez la classe de contexte et cliquez sur Terminer :

Ajout de la migration 2

Notez que les fichiers de script de migration ont été créés. L’étape suivante consiste à exécuter les scripts et à générer la base de données et les tables. Alors, toujours dans l’onglet « Services connectés », cliquez sur les trois points, puis choisissez l’option « Mettre à jour la base de données » et dans la fenêtre suivante cliquez sur « Terminer ».

Mettre à jour la base de données

Après avoir terminé l’exécution de la mise à jour de la base de données, vous pouvez vérifier la base de données et la table créées par EF Core via l’échafaudage :

Vérification de la base de données

Tester l’application

Lançons maintenant l’application et voyons si elle fonctionne comme prévu. Cet article utilise Progress Telerik Un violoniste partout pour faire des requêtes à l’API.

1. Insérer un nouvel enregistrement

Vous pouvez utiliser cet exemple JSON pour insérer un nouvel enregistrement :

{
  "id": "9a27baf2-4f4e-41b1-9b7e-715b7d89656b",
  "name": "Wireless Bluetooth Headphones",
  "description": "High-quality noise-cancelling Bluetooth headphones with 40-hour battery life.",
  "price": 129.99,
  "quantityInStock": 250,
  "sku": "WBH-9876",
  "category": "Electronics",
  "createdAt": "2024-10-12T18:53:42.919Z",
  "isActive": true
}

Insérer un enregistrement

2. Récupération des données

Récupération de données

Conclusion et considérations finales

Comme vous pouvez le constater, l’API fonctionne correctement. Cela montre que toutes les classes et configurations nécessaires pour créer une API CRUD ont été correctement implémentées par les ressources d’échafaudage. La seule classe créée manuellement était la ProductItem classe d’entité.

Les fonctionnalités d’échafaudage disponibles dans ASP.NET Core sont excellentes pour accélérer le processus de développement, car elles évitent le travail répétitif de création de composants de base, tels que les contrôleurs, les classes de configuration EF Core, les chaînes de connexion et autres à partir de modèles de données et de contextes de données définis.

Ceci est particulièrement utile dans les projets qui suivent le modèle MVC (Model-View-Controller), où la génération de code standard peut gagner du temps et réduire les erreurs manuelles. De plus, l’échafaudage permet aux développeurs d’implémenter rapidement les fonctionnalités CRUD (Créer, Lire, Mettre à jour, Supprimer), leur permettant ainsi de se concentrer sur des aspects plus complexes et spécifiques de l’application, tels que les règles métier.

Enfin, l’utilisation d’échafaudages accélère le développement initial sans compromettre la qualité du code, car elle suit les meilleures pratiques recommandées par la plateforme ASP.NET Core elle-même.




Source link