API Web ASP.NET + Entity Framework + Microsoft SQL Server + Angular. Partie 1





introduction



Un court cours sur la création d'une application Web simple à l'aide des technologies ASP.NET Core, Entity Framework, Microsoft SQL Server SGBD et Angular Framework. Nous testerons l'API Web via l'application Postman .



Le cours se compose de plusieurs parties:



  1. Créez des API Web avec l'API Web ASP.NET et Entity Framework Core.
  2. Implémentation de l'interface utilisateur en Angular.
  3. Ajout de l'authentification Ă  l'application.
  4. Étendez le modĂšle d'application et explorez les fonctionnalitĂ©s supplĂ©mentaires d'Entity Framework.


Partie 1. Créer des API Web avec l'API Web ASP.NET et Entity Framework Core



A titre d'exemple, nous considérerons l'application désormais classique d'une liste de tùches. Pour développer l'application, j'utiliserai Visual Studio 2019 (le processus est similaire dans Visual Studio 2017).



Création de projet



Créez un nouveau projet d'application Web ASP.NET Core dans Visual Studio:







nommez l'application et spécifiez le chemin d'accÚs au répertoire avec le projet:







et sélectionnez le modÚle d'application API:







ModĂšle



Créons un catalogue de modÚles et ajoutons la premiÚre classe TodoItem.cs au nouveau catalogue, dont les objets décriront certaines tùches de la liste de tùches dans l'application:



public class TodoItem
{
    public int Id { get; set; }
    public string TaskDescription { get; set; }
    public bool IsComplete { get; set; }
}


Nous utiliserons Sql Server en tant que SGBD, et l'accÚs à la base de données sera effectué via Entity Framework Core et d'abord, nous installerons le framework via le gestionnaire de packages NuGet intégré:







Une approche pour travailler avec Entity Framework est l'approche «Code-First». L'essence de l'approche est que basée sur le modÚle d'application (dans notre cas, le modÚle représente une seule classe - TodoItem.cs), la structure de la base de données (tables, clés primaires, liens) est formée, tout ce travail se fait «en coulisses» et directement avec Nous ne travaillons pas avec SQL. Une condition préalable pour la classe de modÚle est la présence d'un champ de clé primaire; par défaut, Entity Framework recherche un champ entier au nom duquel se trouve une sous-chaßne «id» et forme une clé primaire basée sur celui-ci. Vous pouvez remplacer ce comportement à l'aide d'attributs personnalisés ou à l'aide des fonctionnalités de l'API Fluent.



Le composant principal de l'utilisation d'Entity Framework est la classe de contexte de base de données, à travers laquelle les données des tables sont réellement accessibles:



public class EFTodoDBContext : DbContext
{
    public EFTodoDBContext(DbContextOptions<EFTodoDBContext> options) : base(options) 
    { }
    public DbSet<TodoItem> TodoItems{ get; set; }
}


La classe de base DbContext crée le contexte de la base de données et donne accÚs aux fonctionnalités d'Entity Framework.



Nous utiliserons SQL Server 2017 Express pour stocker les données d'application . Les chaßnes de connexion sont stockées dans un fichier JSON appelé appsettings.json:



{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.\\SQLEXPRESS;Database=Todo;Trusted_Connection=true"
  }
}


Ensuite, vous devez modifier la classe Startup.cs en ajoutant le code suivant à la méthode ConfigureServices ():



services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));


La méthode AddDbContext () configure les services fournis par Entity Framework Core pour la classe de contexte de base de données EFTodoDBContext. L'argument de la méthode AddDbContext () est une expression lambda qui reçoit un objet options qui configure la base de données pour la classe de contexte. Dans ce cas, la base de données est configurée à l'aide de la méthode UseSqlServer () et en spécifiant une chaßne de connexion.



Définissons les opérations de base pour travailler avec des tùches dans l'interface ITodoRepository:



 public interface ITodoRepository
 {
    IEnumerable<TodoItem> Get();
    TodoItem Get(int id);
    void Create(TodoItem item);
    void Update(TodoItem item);
    TodoItem Delete(int id);
 }


Cette interface nous permet de ne pas penser Ă  l'implĂ©mentation spĂ©cifique de l'entrepĂŽt de donnĂ©es, peut-ĂȘtre n'avons-nous pas exactement dĂ©cidĂ© du choix d'un framework SGBD ou ORM, maintenant cela n'a pas d'importance, la classe dĂ©crivant l'accĂšs aux donnĂ©es hĂ©ritera de cette interface.

Implémentons un référentiel qui, comme mentionné précédemment, héritera de ITodoRepository et utilisera EFTodoDBContext comme source de données:



public class EFTodoRepository : ITodoRepository
{
    private EFTodoDBContext Context;
    public IEnumerable<TodoItem> Get()
    {
        return Context.TodoItems;
    }
    public TodoItem Get(int Id)
    {
        return Context.TodoItems.Find(Id);
    }
    public EFTodoRepository(EFTodoDBContext context)
    {
        Context = context;
    }
    public void Create(TodoItem item)
    {
        Context.TodoItems.Add(item);
        Context.SaveChanges();
    }
    public void Update(TodoItem updatedTodoItem)
    {
        TodoItem currentItem = Get(updatedTodoItem.Id);
        currentItem.IsComplete = updatedTodoItem.IsComplete;
        currentItem.TaskDescription = updatedTodoItem.TaskDescription;

        Context.TodoItems.Update(currentItem);
        Context.SaveChanges();
        }

    public TodoItem Delete(int Id)
    {
        TodoItem todoItem = Get(Id);

        if (todoItem != null)
        {
            Context.TodoItems.Remove(todoItem);
            Context.SaveChanges();
        }

        return todoItem;
    }    
}


Manette



Le responsable du traitement, dont la mise en Ɠuvre sera dĂ©crite ci-dessous, ne saura rien sur le contexte des donnĂ©es d'EFTodoDBContext, mais n'utilisera que l'interface ITodoRepository dans son travail, ce qui vous permet de changer la source de donnĂ©es sans changer le contrĂŽleur. Cette approche Adam Freeman dans son livre «Entity Framework Core 2 pour ASP.NET Core MVC pour les professionnels» a appelĂ© le modĂšle «Stockage».



Le contrĂŽleur implĂ©mente des gestionnaires pour les mĂ©thodes de requĂȘte HTTP standard: GET, POST, PUT, DELETE, qui changeront l'Ă©tat de nos tĂąches dĂ©crites dans la classe TodoItem.cs.



Ajoutez la classe TodoController.cs au répertoire Controllers avec le contenu suivant:



[Route("api/[controller]")]
public class TodoController : Controller
{
    ITodoRepository TodoRepository;

    public TodoController(ITodoRepository todoRepository)
    {
        TodoRepository = todoRepository;
    }

    [HttpGet(Name = "GetAllItems")]
    public IEnumerable<TodoItem> Get()
    {
        return TodoRepository.Get();
    }

    [HttpGet("{id}", Name = "GetTodoItem")]
    public IActionResult Get(int Id)
    {
        TodoItem todoItem = TodoRepository.Get(Id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return new ObjectResult(todoItem);
    }

    [HttpPost]
    public IActionResult Create([FromBody] TodoItem todoItem)
     {
        if (todoItem == null)
        {
            return BadRequest();
        }
        TodoRepository.Create(todoItem);
        return CreatedAtRoute("GetTodoItem", new { id = todoItem.Id }, todoItem);
    }

    [HttpPut("{id}")]
    public IActionResult Update(int Id, [FromBody] TodoItem updatedTodoItem)
    {
        if (updatedTodoItem == null || updatedTodoItem.Id != Id)
        {
            return BadRequest();
        }

        var todoItem = TodoRepository.Get(Id);
        if (todoItem == null)
        {
            return NotFound();
        }

        TodoRepository.Update(updatedTodoItem);
        return RedirectToRoute("GetAllItems");
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int Id)
    {
        var deletedTodoItem = TodoRepository.Delete(Id);

        if (deletedTodoItem == null)
        {
            return BadRequest();
        }

        return new ObjectResult(deletedTodoItem);
    }
 }


Avant la définition de classe, un attribut décrivant le modÚle de route pour accéder au contrÎleur est spécifié: [Route ("api / [controller]")]. Le TodoController sera accessible via la route suivante: https: // <ip hÎte>: <port> / api / todo. [Controller] spécifie le nom de la classe de contrÎleur en minuscules, en omettant la partie "Controller".



Avant chaque dĂ©finition de mĂ©thode dans TodoController, un attribut spĂ©cial de la forme: [<HTTP method> ("parameter", Name = "method alias")] est spĂ©cifiĂ©. L'attribut dĂ©termine quelle requĂȘte HTTP sera traitĂ©e par cette mĂ©thode, le paramĂštre qui est passĂ© dans l'URI de la requĂȘte et l'alias de la mĂ©thode avec laquelle la requĂȘte peut ĂȘtre renvoyĂ©e. Si vous ne spĂ©cifiez pas l'attribut, le framework MVC essaiera par dĂ©faut de trouver la mĂ©thode la plus appropriĂ©e dans le contrĂŽleur pour traiter la requĂȘte en fonction du nom de la mĂ©thode et des paramĂštres spĂ©cifiĂ©s dans la requĂȘte, donc si vous ne spĂ©cifiez pas d'attribut pour la mĂ©thode Get () dans le contrĂŽleur TodoController, alors dans une requĂȘte HTTP en utilisant la mĂ©thode GET: https: // <ip hĂŽte>: <port> / api / todo, l'infrastructure dĂ©finira la mĂ©thode Get () du contrĂŽleur pour traiter la requĂȘte.



Dans son constructeur, le contrÎleur reçoit une référence à un objet de type ITodoRepository, mais jusqu'ici l'infrastructure MVC ne sait pas quel objet substituer lors de la création du contrÎleur. Nous devons créer un service qui résout de maniÚre unique cette dépendance, pour cela, nous apporterons des modifications à la classe Startup.cs en ajoutant le code suivant à la méthode ConfigureServices ():



services.AddTransient<ITodoRepository, EFTodoRepository>();


La méthode AddTransient <ITodoRepository, EFTodoRepository> () définit un service qui crée une nouvelle instance de la classe EFTodoRepository chaque fois qu'une instance de type ITodoRepository est requise, par exemple dans un contrÎleur.



Code complet de la classe Startup.cs:



public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
        services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
        services.AddTransient<ITodoRepository, EFTodoRepository>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
 }


Migrations



Pour que Entity Framework gĂ©nĂšre la base de donnĂ©es et les tables Ă  partir du modĂšle, vous devez utiliser le processus de migration de base de donnĂ©es. Les migrations sont un groupe de commandes qui prĂ©pare la base de donnĂ©es Ă  fonctionner avec Entity Framework. Ils sont utilisĂ©s pour crĂ©er et synchroniser la base de donnĂ©es. Les commandes peuvent ĂȘtre exĂ©cutĂ©es Ă  la fois dans la console du gestionnaire de package et dans Power Shell (Developer Power Shell). Nous utiliserons la console du gestionnaire de package, pour travailler avec Entity Framework, nous devons installer le package Microsoft.EntityFrameworkCore.Tools:







Lancez la console du gestionnaire de package et exécutez la commande Add-Migration Initial :











Un nouveau répertoire apparaßtra dans le projet - Migrations, dans lequel les classes de migration seront stockées, sur la base des objets de la base de données qui seront créés aprÚs l'exécution de la commande Update-Database: L'







API Web est prĂȘte, en exĂ©cutant l'application sur IIS Express local, nous pouvons tester le contrĂŽleur.



Tester WebAPI



CrĂ©ons une nouvelle collection de requĂȘtes dans Postman appelĂ©e TodoWebAPI:







Puisque notre base de donnĂ©es est vide, testons d'abord la crĂ©ation d'une nouvelle tĂąche. Dans le contrĂŽleur, la mĂ©thode Create () est responsable de la crĂ©ation de tĂąches, qui traiteront une requĂȘte HTTP envoyĂ©e par la mĂ©thode POST et contiendra un objet TodoItem sĂ©rialisĂ© au format JSON dans le corps de la requĂȘte. L'attribut [FromBody] avant le paramĂštre todoItem dans la mĂ©thode Create () indique au framework MVC de dĂ©sĂ©rialiser l'objet TodoItem du corps de la requĂȘte et de le transmettre en tant que paramĂštre Ă  la mĂ©thode. CrĂ©ons une requĂȘte dans Postman qui enverra une requĂȘte Ă  la webAPI pour crĂ©er une nouvelle tĂąche:







La méthode Create () aprÚs la création réussie de la tùche redirige la demande vers la méthode Get () avec l'alias "GetTodoItem" et transmet l'ID de la tùche nouvellement créée en tant que paramÚtre, à la suite de quoi nous recevrons l'objet de tùche créé au format JSON en réponse à la demande.



En envoyant une requĂȘte HTTP Ă  l'aide de la mĂ©thode PUT et en spĂ©cifiant un objet dĂ©jĂ  crĂ©Ă© dans l'URI Id (https: // localhost: 44370 / api / todo / 1), et en passant un objet avec quelques modifications au format JSON dans le corps de la requĂȘte, nous modifierons cet objet dans la base de donnĂ©es :







Avec une requĂȘte HTTP avec la mĂ©thode GET sans spĂ©cifier de paramĂštres, nous recevrons tous les objets de la base de donnĂ©es:







Une requĂȘte HTTP avec la mĂ©thode DELETE et en spĂ©cifiant l'ID de l'objet dans l'URI (https: // localhost: 44370 / api / todo / 2), supprimera l'objet de la base de donnĂ©es et retournera JSON avec tĂąche distante:







C'est tout, dans la partie suivante, nous implémenterons l'interface utilisateur en utilisant le framework Angular JavaScript.



All Articles