Créer des services backend pour les applications mobiles natives avec ASP.NET CoreCreate backend services for native mobile apps with ASP.NET Core

Par Steve SmithBy Steve Smith

Les applications mobiles peuvent communiquer avec les services back-end ASP.NET Core.Mobile apps can communicate with ASP.NET Core backend services. Pour obtenir des instructions sur la connexion de services web locaux à partir de simulateurs iOS et d’émulateurs Android, consultez Se connecter à des services web locaux à partir de simulateurs iOS et d’émulateurs Android.For instructions on connecting local web services from iOS simulators and Android emulators, see Connect to Local Web Services from iOS Simulators and Android Emulators.

Afficher ou télécharger l’exemple de code de services backendView or download sample backend services code

Exemple d’application mobile nativeThe Sample Native Mobile App

Ce didacticiel montre comment créer des services backend en utilisant ASP.NET Core MVC pour prendre en charge des applications mobiles natives.This tutorial demonstrates how to create backend services using ASP.NET Core MVC to support native mobile apps. Il utilise l’application Xamarin.Forms TodoREST comme client natif, qui inclut des clients natifs distincts pour les appareils Android, iOS, Windows universel et Windows Phone.It uses the Xamarin Forms ToDoRest app as its native client, which includes separate native clients for Android, iOS, Windows Universal, and Window Phone devices. Vous pouvez suivre le didacticiel lié pour créer l’application native (et installer les outils Xamarin gratuits nécessaires), ainsi que télécharger l’exemple de solution Xamarin.You can follow the linked tutorial to create the native app (and install the necessary free Xamarin tools), as well as download the Xamarin sample solution. L’exemple Xamarin inclut un projet de services ASP.NET API web 2, que l’application ASP.NET Core de cet article remplace (sans que des modifications soient requises par le client).The Xamarin sample includes an ASP.NET Web API 2 services project, which this article's ASP.NET Core app replaces (with no changes required by the client).

Application TodoREST s’exécutant sur un smartphone Android

FonctionnalitésFeatures

L’application TodoREST prend en charge l’affichage, l’ajout, la suppression et la mise à jour d’éléments de tâche à effectuer.The ToDoRest app supports listing, adding, deleting, and updating To-Do items. Chaque élément a un ID, un nom, des notes et une propriété qui indique si elle est déjà effectuée.Each item has an ID, a Name, Notes, and a property indicating whether it's been Done yet.

La vue principale des éléments, reproduite ci-dessus, montre le nom de chaque élément et indique si la tâche est effectuée avec une marque.The main view of the items, as shown above, lists each item's name and indicates if it's done with a checkmark.

Le fait d’appuyer sur l'icône+ ouvre une boîte de dialogue permettant l’ajout d’un élément :Tapping the + icon opens an add item dialog:

Boîte de dialogue pour ajouter un élément

Le fait de cliquer sur un élément de l’écran de la liste principale ouvre une boîte de dialogue où les valeurs pour Name, Notes et Done peuvent être modifiées, et où vous pouvez supprimer l’élément :Tapping an item on the main list screen opens up an edit dialog where the item's Name, Notes, and Done settings can be modified, or the item can be deleted:

Boîte de dialogue pour modifier un élément

Cet exemple est configuré par défaut pour utiliser les services backend hébergés sur developer.xamarin.com, qui autorisent des opérations en lecture seule.This sample is configured by default to use backend services hosted at developer.xamarin.com, which allow read-only operations. Pour le tester vous-même par rapport à l’application ASP.NET Core créée dans la section suivante et exécuté sur votre ordinateur, vous devez mettre à jour la constante RestUrl de l’application.To test it out yourself against the ASP.NET Core app created in the next section running on your computer, you'll need to update the app's RestUrl constant. Accédez au projet ToDoREST et ouvrez le fichier Constants.cs.Navigate to the ToDoREST project and open the Constants.cs file. Remplacez RestUrl par une URL qui inclut l’adresse IP de votre ordinateur (pas localhost ni 127.0.0.1, car cette adresse est utilisée depuis l’émulateur d’appareil, et non pas depuis votre ordinateur).Replace the RestUrl with a URL that includes your machine's IP address (not localhost or 127.0.0.1, since this address is used from the device emulator, not from your machine). Incluez également le numéro de port (5000).Include the port number as well (5000). Pour tester que vos services fonctionnent avec un appareil, vérifiez que vous n’avez pas un pare-feu actif bloquant l’accès à ce port.In order to test that your services work with a device, ensure you don't have an active firewall blocking access to this port.

// URL of REST service (Xamarin ReadOnly Service)
//public static string RestUrl = "http://developer.xamarin.com:8081/api/todoitems{0}";

// use your machine's IP address
public static string RestUrl = "http://192.168.1.207:5000/api/todoitems/{0}";

Création du projet ASP.NET CoreCreating the ASP.NET Core Project

réez une application web ASP.NET Core dans Visual Studio.Create a new ASP.NET Core Web Application in Visual Studio. Choisissez le modèle "API web" et Pas d’authentification.Choose the Web API template and No Authentication. Nommez le projet ToDoApi.Name the project ToDoApi.

Boîte de dialogue Nouvelle application web ASP.NET avec le modèle de projet API web sélectionné

L’application doit répondre à toutes les demandes adressées au port 5000.The application should respond to all requests made to port 5000. Pour cela, mettez à jour Program.cs en y incluant .UseUrls("http://*:5000") :Update Program.cs to include .UseUrls("http://*:5000") to achieve this:

var host = new WebHostBuilder()
    .UseKestrel()
    .UseUrls("http://*:5000")
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

Notes

Vérifiez que vous exécutez l’application directement et non pas derrière IIS Express, qui ignore par défaut les demandes non locales.Make sure you run the application directly, rather than behind IIS Express, which ignores non-local requests by default. Exécutez dotnet run à partir d’une invite de commandes, ou choisissez le profil du nom d’application dans la liste déroulante Cible de débogage dans la barre d’outils de Visual Studio.Run dotnet run from a command prompt, or choose the application name profile from the Debug Target dropdown in the Visual Studio toolbar.

Ajoutez une classe de modèle pour représenter des éléments de tâche à effectuer.Add a model class to represent To-Do items. Marquez les champs obligatoires en utilisant l’attribut [Required] :Mark required fields using the [Required] attribute:

using System.ComponentModel.DataAnnotations;

namespace ToDoApi.Models
{
    public class ToDoItem
    {
        [Required]
        public string ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Notes { get; set; }

        public bool Done { get; set; }
    }
}

Les méthodes d’API requièrent un moyen d’utiliser des données.The API methods require some way to work with data. Utilisez la même interface IToDoRepository que celle utilisée par l’exemple Xamarin d’origine :Use the same IToDoRepository interface the original Xamarin sample uses:

using System.Collections.Generic;
using ToDoApi.Models;

namespace ToDoApi.Interfaces
{
    public interface IToDoRepository
    {
        bool DoesItemExist(string id);
        IEnumerable<ToDoItem> All { get; }
        ToDoItem Find(string id);
        void Insert(ToDoItem item);
        void Update(ToDoItem item);
        void Delete(string id);
    }
}

Pour cet exemple, l’implémentation utilise simplement une collection privée d’éléments :For this sample, the implementation just uses a private collection of items:

using System.Collections.Generic;
using System.Linq;
using ToDoApi.Interfaces;
using ToDoApi.Models;

namespace ToDoApi.Services
{
    public class ToDoRepository : IToDoRepository
    {
        private List<ToDoItem> _toDoList;

        public ToDoRepository()
        {
            InitializeData();
        }

        public IEnumerable<ToDoItem> All
        {
            get { return _toDoList; }
        }

        public bool DoesItemExist(string id)
        {
            return _toDoList.Any(item => item.ID == id);
        }

        public ToDoItem Find(string id)
        {
            return _toDoList.FirstOrDefault(item => item.ID == id);
        }

        public void Insert(ToDoItem item)
        {
            _toDoList.Add(item);
        }

        public void Update(ToDoItem item)
        {
            var todoItem = this.Find(item.ID);
            var index = _toDoList.IndexOf(todoItem);
            _toDoList.RemoveAt(index);
            _toDoList.Insert(index, item);
        }

        public void Delete(string id)
        {
            _toDoList.Remove(this.Find(id));
        }

        private void InitializeData()
        {
            _toDoList = new List<ToDoItem>();

            var todoItem1 = new ToDoItem
            {
                ID = "6bb8a868-dba1-4f1a-93b7-24ebce87e243",
                Name = "Learn app development",
                Notes = "Attend Xamarin University",
                Done = true
            };

            var todoItem2 = new ToDoItem
            {
                ID = "b94afb54-a1cb-4313-8af3-b7511551b33b",
                Name = "Develop apps",
                Notes = "Use Xamarin Studio/Visual Studio",
                Done = false
            };

            var todoItem3 = new ToDoItem
            {
                ID = "ecfa6f80-3671-4911-aabe-63cc442c1ecf",
                Name = "Publish apps",
                Notes = "All app stores",
                Done = false,
            };

            _toDoList.Add(todoItem1);
            _toDoList.Add(todoItem2);
            _toDoList.Add(todoItem3);
        }
    }
}

Configurez l’implémentation dans Startup.cs :Configure the implementation in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddSingleton<IToDoRepository,ToDoRepository>();
}

À ce stade, vous êtes prêt à créer le ToDoItemsController.At this point, you're ready to create the ToDoItemsController.

Conseil

Découvrez plus en détail comment créer des API web dans Créer votre première API web avec ASP.NET Core MVC et Visual Studio.Learn more about creating web APIs in Build your first Web API with ASP.NET Core MVC and Visual Studio.

Création du contrôleurCreating the Controller

Ajoutez un nouveau contrôleur au projet, ToDoItemsController.Add a new controller to the project, ToDoItemsController. Il doit hériter de Microsoft.AspNetCore.Mvc.Controller.It should inherit from Microsoft.AspNetCore.Mvc.Controller. Ajoutez un attribut Route pour indiquer que le contrôleur gère les demandes effectuées via des chemins commençant par api/todoitems.Add a Route attribute to indicate that the controller will handle requests made to paths starting with api/todoitems. Le jeton [controller] de la route est remplacé par le nom du contrôleur (en omettant le suffixe Controller) et est particulièrement pratique pour les routes globales.The [controller] token in the route is replaced by the name of the controller (omitting the Controller suffix), and is especially helpful for global routes. Découvrez plus d’informations sur le routage.Learn more about routing.

Le contrôleur nécessite un IToDoRepository pour fonctionner ; demandez une instance de ce type via le constructeur du contrôleur.The controller requires an IToDoRepository to function; request an instance of this type through the controller's constructor. À l’exécution, cette instance est fournie via la prise en charge par l’infrastructure de l’injection de dépendances.At runtime, this instance will be provided using the framework's support for dependency injection.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ToDoApi.Interfaces;
using ToDoApi.Models;

namespace ToDoApi.Controllers
{
    [Route("api/[controller]")]
    public class ToDoItemsController : Controller
    {
        private readonly IToDoRepository _toDoRepository;

        public ToDoItemsController(IToDoRepository toDoRepository)
        {
            _toDoRepository = toDoRepository;
        }

Cette API prend en charge quatre verbes HTTP différents pour effectuer des opérations CRUD (création, lecture, mise à jour, suppression) sur la source de données.This API supports four different HTTP verbs to perform CRUD (Create, Read, Update, Delete) operations on the data source. La plus simple d’entre elles est l’opération de lecture, qui correspond à une requête HTTP GET.The simplest of these is the Read operation, which corresponds to an HTTP GET request.

Lecture d’élémentsReading Items

Demander une liste d’éléments se fait via une requête GET à la méthode List.Requesting a list of items is done with a GET request to the List method. L’attribut [HttpGet] sur la méthode List indique que cette action doit gérer seulement les requêtes GET.The [HttpGet] attribute on the List method indicates that this action should only handle GET requests. La route pour cette action est la route spécifiée sur le contrôleur.The route for this action is the route specified on the controller. Le nom de l’action ne doit pas nécessairement constituer une partie de la route.You don't necessarily need to use the action name as part of the route. Il vous suffit de faire en sorte que chaque action ait une route unique et non ambiguë.You just need to ensure each action has a unique and unambiguous route. Des attributs de routage peuvent être appliqués aux niveaux du contrôleur et des méthodes pour créer des routes spécifiques.Routing attributes can be applied at both the controller and method levels to build up specific routes.

[HttpGet]
public IActionResult List()
{
    return Ok(_toDoRepository.All);
}

La méthode List retourne un code de réponse 200 OK et tous les éléments de tâche à effectuer, sérialisés au format JSON.The List method returns a 200 OK response code and all of the ToDo items, serialized as JSON.

Vous pouvez tester votre nouvelle méthode d’API via différents outils, comme Postman, qui est montré ici :You can test your new API method using a variety of tools, such as Postman, shown here:

Console de Postman montrant une requête GET pour les éléments de tâche à effectuer (todoitems) et le corps de la réponse montrant le JSON pour les trois éléments retournés

Création d’élémentsCreating Items

Par convention, la création d’éléments de données est mappée au verbe HTTP POST.By convention, creating new data items is mapped to the HTTP POST verb. Un attribut [HttpPost] est appliqué à la méthode Create, laquelle accepte une instance de ToDoItem.The Create method has an [HttpPost] attribute applied to it, and accepts a ToDoItem instance. Comme l’argument item sera passé dans le corps de la requête POST, ce paramètre est décoré avec l’attribut [FromBody].Since the item argument will be passed in the body of the POST, this parameter is decorated with the [FromBody] attribute.

À l’intérieur de la méthode, la validité et l’existence préalable de l’élément dans le magasin de données sont vérifiées et, si aucun problème ne se produit, il est ajouté via le référentiel.Inside the method, the item is checked for validity and prior existence in the data store, and if no issues occur, it's added using the repository. La vérification ModelState.IsValid effectue la validation du modèle et doit être effectuée dans chaque méthode d’API qui accepte une entrée utilisateur.Checking ModelState.IsValid performs model validation, and should be done in every API method that accepts user input.

[HttpPost]
public IActionResult Create([FromBody] ToDoItem item)
{
    try
    {
        if (item == null || !ModelState.IsValid)
        {
            return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
        }
        bool itemExists = _toDoRepository.DoesItemExist(item.ID);
        if (itemExists)
        {
            return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
        }
        _toDoRepository.Insert(item);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
    }
    return Ok(item);
}

L’exemple utilise une énumération contenant les codes d’erreur qui sont passés au client mobile :The sample uses an enum containing error codes that are passed to the mobile client:

public enum ErrorCode
{
    TodoItemNameAndNotesRequired,
    TodoItemIDInUse,
    RecordNotFound,
    CouldNotCreateItem,
    CouldNotUpdateItem,
    CouldNotDeleteItem
}

Testez en ajoutant de nouveaux éléments avec Postman, en choisissant le verbe POST qui fournit le nouvel objet au format JSON dans le corps de la requête.Test adding new items using Postman by choosing the POST verb providing the new object in JSON format in the Body of the request. Vous devez également ajouter un en-tête de requête spécifiant un Content-Type de application/json.You should also add a request header specifying a Content-Type of application/json.

Console de Postman montrant un POST et la réponse

La méthode retourne l’élément qui vient d’être créé dans la réponse.The method returns the newly created item in the response.

Mise à jour d’élémentsUpdating Items

La modification des enregistrements est effectuée via des requêtes HTTP PUT.Modifying records is done using HTTP PUT requests. Outre cette modification, la méthode Edit est presque identique à Create.Other than this change, the Edit method is almost identical to Create. Notez que si l’enregistrement n’est pas trouvé, l’action Edit retourne une réponse NotFound (404).Note that if the record isn't found, the Edit action will return a NotFound (404) response.

[HttpPut]
public IActionResult Edit([FromBody] ToDoItem item)
{
    try
    {
        if (item == null || !ModelState.IsValid)
        {
            return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
        }
        var existingItem = _toDoRepository.Find(item.ID);
        if (existingItem == null)
        {
            return NotFound(ErrorCode.RecordNotFound.ToString());
        }
        _toDoRepository.Update(item);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
    }
    return NoContent();
}

Pour tester avec Postman, changez le verbe en PUT.To test with Postman, change the verb to PUT. Spécifiez les données de l’objet mis à jour dans le corps de la requête.Specify the updated object data in the Body of the request.

Console de Postman montrant un PUT et la réponse

Cette méthode retourne une réponse NoContent (204) en cas de réussite, pour des raisons de cohérence avec l’API préexistante.This method returns a NoContent (204) response when successful, for consistency with the pre-existing API.

Suppression d’élémentsDeleting Items

La suppression d’enregistrements est effectuée via des requêtes DELETE adressées au service, en passant l’ID de l’élément à supprimer.Deleting records is accomplished by making DELETE requests to the service, and passing the ID of the item to be deleted. Comme pour les mises à jour, les requêtes pour des éléments qui n’existent pas reçoivent des réponses NotFound.As with updates, requests for items that don't exist will receive NotFound responses. Sinon, une requête qui réussit obtient une réponse NoContent (204).Otherwise, a successful request will get a NoContent (204) response.

[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
    try
    {
        var item = _toDoRepository.Find(id);
        if (item == null)
        {
            return NotFound(ErrorCode.RecordNotFound.ToString());
        }
        _toDoRepository.Delete(id);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
    }
    return NoContent();
}

Notez que quand vous testez les fonctionnalités de suppression, rien n’est obligatoire dans le corps de la requête.Note that when testing the delete functionality, nothing is required in the Body of the request.

Console de Postman montrant un DELETE et la réponse

Conventions des API web courantesCommon Web API Conventions

Quand vous développez des services backend pour votre application, vous souhaitez obtenir un ensemble cohérent de conventions ou de stratégies pour gérer les problèmes transversaux.As you develop the backend services for your app, you will want to come up with a consistent set of conventions or policies for handling cross-cutting concerns. Par exemple, dans le service montré ci-dessus, les requêtes pour des enregistrements spécifiques qui n’ont pas été trouvés ont reçu une réponse NotFound et non pas une réponse BadRequest.For example, in the service shown above, requests for specific records that weren't found received a NotFound response, rather than a BadRequest response. De même, les commandes envoyées à ce service qui ont passé des types liés au modèle ont toujours vérifié ModelState.IsValid et retourné un BadRequest pour les types de modèle non valide.Similarly, commands made to this service that passed in model bound types always checked ModelState.IsValid and returned a BadRequest for invalid model types.

Une fois que vous avez identifié une stratégie commune pour vos API, vous pouvez en général l’encapsuler dans un filtre.Once you've identified a common policy for your APIs, you can usually encapsulate it in a filter. Découvrez plus d’informations sur la façon d’encapsuler des stratégies d’API courantes dans les applications ASP.NET Core MVC.Learn more about how to encapsulate common API policies in ASP.NET Core MVC applications.

Ressources supplémentairesAdditional resources