Création d’un point de terminaison OData v3 avec l’API web 2

par Mike Wasson

Télécharger le projet terminé

Le protocole OData (Open Data Protocol ) est un protocole d’accès aux données pour le web. OData fournit un moyen uniforme de structurer les données, d’interroger les données et de manipuler le jeu de données par le biais d’opérations CRUD (créer, lire, mettre à jour et supprimer). OData prend en charge les formats AtomPub (XML) et JSON. OData définit également un moyen d’exposer les métadonnées relatives aux données. Les clients peuvent utiliser les métadonnées pour découvrir les informations de type et les relations pour le jeu de données.

API Web ASP.NET facilite la création d’un point de terminaison OData pour un jeu de données. Vous pouvez contrôler exactement les opérations OData que le point de terminaison prend en charge. Vous pouvez héberger plusieurs points de terminaison OData, ainsi que des points de terminaison non-OData. Vous disposez d’un contrôle total sur votre modèle de données, la logique métier back-end et la couche de données.

Versions logicielles utilisées dans le tutoriel

La prise en charge de l’API web OData a été ajoutée dans ASP.NET et Web Tools mise à jour 2012.2. Toutefois, ce didacticiel utilise la génération automatique qui a été ajoutée dans Visual Studio 2013.

Dans ce tutoriel, vous allez créer un point de terminaison OData simple que les clients peuvent interroger. Vous allez également créer un client C# pour le point de terminaison. Une fois ce didacticiel terminé, l’ensemble de didacticiels suivant montre comment ajouter d’autres fonctionnalités, notamment des relations d’entité, des actions et des $expand/$select.

Créer le projet Visual Studio

Dans ce tutoriel, vous allez créer un point de terminaison OData qui prend en charge les opérations CRUD de base. Le point de terminaison expose une seule ressource, une liste de produits. Les didacticiels ultérieurs ajouteront d’autres fonctionnalités.

Démarrez Visual Studio et sélectionnez Nouveau projet dans la page Démarrer. Ou, dans le menu Fichier , sélectionnez Nouveau , puis Projet.

Dans le volet Modèles , sélectionnez Modèles installés et développez le nœud Visual C#. Sous Visual C#, sélectionnez Web. Sélectionnez le modèle d’application web ASP.NET .

Capture d’écran de la fenêtre du nouveau projet, montrant le chemin d’accès au volet modèle et affichant des instructions mises en surbrillance pour sélectionner l’option Application web A S P.P. dot NET.

Dans la boîte de dialogue Nouveau projet ASP.NET , sélectionnez le modèle Vide . Sous « Ajouter des dossiers et des références principales pour... », case activée API web. Cliquez sur OK.

Capture d’écran de la boîte de dialogue projet A SP dot NET, montrant les zones d’options de modèle et mettant en surbrillance l’option « vide ».

Ajouter un modèle d’entité

Un modèle est un objet qui représente les données dans votre application. Pour ce tutoriel, nous avons besoin d’un modèle qui représente un produit. Le modèle correspond à notre type d’entité OData.

Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Modèles. Dans le menu contextuel, sélectionnez Ajouter, puis Classe.

Capture d’écran de la boîte de dialogue Explorateur de solutions, montrant la liste des menus de chaque sélection, à mesure qu’elle met en surbrillance chacune, en tête de l’option de classe.

Dans la boîte de dialogue Ajouter un nouvel élément, nommez la classe « Product ».

Capture d’écran de la fenêtre « ajouter un nouveau projet », affichant le tri par défaut et montrant l’option de classe, et les mots « product dot c s » dans le champ vide ci-dessous.

Notes

Par convention, les classes de modèle sont placées dans le dossier Models. Vous n’êtes pas obligé de suivre cette convention dans vos propres projets, mais nous allons l’utiliser pour ce tutoriel.

Dans le fichier Product.cs, ajoutez la définition de classe suivante :

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

La propriété ID sera la clé d’entité. Les clients peuvent interroger les produits par ID. Ce champ serait également la clé primaire dans la base de données principale.

Générez le projet maintenant. À l’étape suivante, nous allons utiliser une structure de Visual Studio qui utilise la réflexion pour trouver le type Product.

Ajouter un contrôleur OData

Un contrôleur est une classe qui gère les requêtes HTTP. Vous définissez un contrôleur distinct pour chaque ensemble d’entités dans votre service OData. Dans ce tutoriel, nous allons créer un seul contrôleur.

Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Contrôleurs. Sélectionnez Ajouter, puis Contrôleur.

Capture d’écran de la fenêtre de l’Explorateur de solutions, qui met en évidence l’option de contrôleur qui affiche ensuite les menus permettant d’ajouter un contrôleur de données O.

Dans la boîte de dialogue Ajouter une structure , sélectionnez « Contrôleur OData API Web 2 avec actions, à l’aide d’Entity Framework ».

Capture d’écran de l’écran « Ajouter une structure », montrant le menu des options du contrôleur et mettant en évidence le contrôleur de données Web A P I2 O.

Dans la boîte de dialogue Ajouter un contrôleur , nommez le contrôleur « ProductsController ». Cochez la case « Utiliser des actions de contrôleur asynchrones ». Dans la liste déroulante Modèle , sélectionnez la classe Product.

Capture d’écran de la boîte de dialogue Ajouter un contrôleur, affichant des champs pour le nom du contrôleur, la liste déroulante classe de modèle et la classe de contexte de données.

Cliquez sur le bouton Nouveau contexte de données... . Conservez le nom par défaut du type de contexte de données, puis cliquez sur Ajouter.

Capture d’écran de la fenêtre nouveau contexte de données, montrant un champ pour « nouveau type de contexte de données » et montrant le nom par défaut du type de contexte de données.

Cliquez sur Ajouter dans la boîte de dialogue Ajouter un contrôleur pour ajouter le contrôleur.

Capture d’écran de la boîte de dialogue Ajouter un contrôleur, montrant les différentes exigences de champ, avec une case à cocher « utiliser des actions de contrôleur asynchrones ».

Remarque : si vous obtenez un message d’erreur indiquant « Une erreur s’est produite lors de l’obtention du type... », assurez-vous que vous avez généré le projet Visual Studio après avoir ajouté la classe Product. La génération de modèles automatique utilise la réflexion pour rechercher la classe .

Capture d’écran de Microsoft Visual Studio, affichant un « X » cerclé rouge, suivi du mot « error » et d’un message détaillé de l’erreur.

La génération automatique ajoute deux fichiers de code au projet :

  • Products.cs définit le contrôleur d’API web qui implémente le point de terminaison OData.
  • ProductServiceContext.cs fournit des méthodes pour interroger la base de données sous-jacente, à l’aide d’Entity Framework.

Capture d’écran de la fenêtre du projet, montrant le menu service du produit et circonstant les deux fichiers nouvellement ajoutés sous les contrôleurs et sous les modèles.

Ajouter l’EDM et l’itinéraire

Dans Explorateur de solutions, développez le dossier App_Start et ouvrez le fichier nommé WebApiConfig.cs. Cette classe contient le code de configuration pour l’API web. Remplacez ce code par ce qui suit :

using ProductService.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;

namespace ProductService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Product>("Products");
            config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}

Ce code effectue deux opérations :

  • Crée un modèle de données d’entité (EDM) pour le point de terminaison OData.
  • Ajoute un itinéraire pour le point de terminaison.

Un EDM est un modèle abstrait des données. L’EDM est utilisé pour créer le document de métadonnées et définir les URI du service. ODataConventionModelBuilder crée un EDM à l’aide d’un ensemble de conventions de nomm par défaut. Cette approche nécessite le moins de code. Si vous souhaitez plus de contrôle sur l’EDM, vous pouvez utiliser la classe ODataModelBuilder pour créer l’EDM en ajoutant explicitement des propriétés, des clés et des propriétés de navigation.

La méthode EntitySet ajoute un jeu d’entités à l’EDM :

modelBuilder.EntitySet<Product>("Products");

La chaîne « Products » définit le nom du jeu d’entités. Le nom du contrôleur doit correspondre au nom du jeu d’entités. Dans ce didacticiel, l’ensemble d’entités est nommé « Products » et le contrôleur est nommé ProductsController. Si vous avez nommé l’ensemble d’entités « ProductSet », vous devez nommer le contrôleur ProductSetController. Notez qu’un point de terminaison peut avoir plusieurs ensembles d’entités. Appelez EntitySet<T> pour chaque jeu d’entités, puis définissez un contrôleur correspondant.

La méthode MapODataRoute ajoute un itinéraire pour le point de terminaison OData.

config.Routes.MapODataRoute("ODataRoute", "odata", model);

Le premier paramètre est un nom convivial pour la route. Les clients de votre service ne voient pas ce nom. Le deuxième paramètre est le préfixe URI du point de terminaison. Compte tenu de ce code, l’URI du jeu d’entités Products est http:// hostname/odata/Products. Votre application peut avoir plusieurs points de terminaison OData. Pour chaque point de terminaison, appelez MapODataRoute et fournissez un nom d’itinéraire unique et un préfixe d’URI unique.

Amorçage de la base de données (facultatif)

Dans cette étape, vous allez utiliser Entity Framework pour amorçage de la base de données avec des données de test. Cette étape est facultative, mais elle vous permet de tester immédiatement votre point de terminaison OData.

Dans le menu Outils , sélectionnez Gestionnaire de package NuGet, puis console du gestionnaire de package. Dans la fenêtre Console du Gestionnaire de package, entrez la commande suivante :

Enable-Migrations

Cela ajoute un dossier nommé Migrations et un fichier de code nommé Configuration.cs.

Capture d’écran du menu du service produit de l’Explorateur de solutions, circonstant le dossier récemment ajouté appelé migrations et montrant le fichier qu’il contient.

Ouvrez ce fichier et ajoutez le code suivant à la Configuration.Seed méthode .

protected override void Seed(ProductService.Models.ProductServiceContext context)
{
    // New code 
    context.Products.AddOrUpdate(new Product[] {
        new Product() { ID = 1, Name = "Hat", Price = 15, Category = "Apparel" },
        new Product() { ID = 2, Name = "Socks", Price = 5, Category = "Apparel" },
        new Product() { ID = 3, Name = "Scarf", Price = 12, Category = "Apparel" },
        new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Category = "Toys" },
        new Product() { ID = 5, Name = "Puzzle", Price = 8, Category = "Toys" },
    });
}

Dans la fenêtre Console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration Initial
Update-Database

Ces commandes génèrent le code qui crée la base de données, puis exécutent ce code.

Exploration du point de terminaison OData

Dans cette section, nous allons utiliser le proxy de débogage web Fiddler pour envoyer des requêtes au point de terminaison et examiner les messages de réponse. Cela vous aidera à comprendre les fonctionnalités d’un point de terminaison OData.

Dans Visual Studio, appuyez sur F5 pour démarrer le débogage. Par défaut, Visual Studio ouvre votre navigateur sur http://localhost:*port*, où port correspond au numéro de port configuré dans les paramètres du projet.

Vous pouvez modifier le numéro de port dans les paramètres du projet. Dans Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Propriétés. Dans la fenêtre propriétés, sélectionnez Web. Entrez le numéro de port sous Url du projet.

Service Document

Le document de service contient la liste des jeux d’entités pour le point de terminaison OData. Pour obtenir le document de service, envoyez une requête GET à l’URI racine du service.

À l’aide de Fiddler, entrez l’URI suivant sous l’onglet Composer : http://localhost:port/odata/, où port est le numéro de port.

Capture d’écran de la fenêtre de document de service, affichant les différents onglets avec l’onglet « analysé » choisi et montrant les données u R L dans le champ compositeur.

Cliquez sur le bouton Exécuter . Fiddler envoie une requête HTTP GET à votre application. Vous devez voir la réponse dans la liste Sessions web. Si tout fonctionne, le code status sera 200.

Capture d’écran de la liste des sessions web, montrant le protocole H TT P avec le numéro de résultat 200, ainsi que l’adresse u R L et l’hôte.

Double-cliquez sur la réponse dans la liste Sessions web pour afficher les détails du message de réponse sous l’onglet Inspecteurs.

Capture d’écran de l’onglet inspecteur de la liste des sessions web, affichant la réponse des en-têtes de requête et les informations X M L.

Le message de réponse HTTP brut doit ressembler à ce qui suit :

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/atomsvc+xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 17:51:01 GMT
Content-Length: 364

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:60868/odata" 
    xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title type="text">Default</atom:title>
    <collection href="Products">
        <atom:title type="text">Products</atom:title>
    </collection>
    </workspace>
</service></pre>

Par défaut, l’API web retourne le document de service au format AtomPub. Pour demander JSON, ajoutez l’en-tête suivant à la requête HTTP :

Accept: application/json

Capture d’écran de la fenêtre sessions web, montrant la réponse de l’adresse ip dans la section En-têtes de requête, et circonclant où écrire la demande j son.

À présent, la réponse HTTP contient une charge utile JSON :

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 22:59:28 GMT
Content-Length: 136

{
  "odata.metadata":"http://localhost:60868/odata/$metadata","value":[
    {
      "name":"Products","url":"Products"
    }
  ]
}

Document sur les métadonnées de service

Le document de métadonnées de service décrit le modèle de données du service, à l’aide d’un langage XML appelé CSDL (Conceptual Schema Definition Language). Le document de métadonnées montre la structure des données dans le service et peut être utilisé pour générer du code client.

Pour obtenir le document de métadonnées, envoyez une demande GET à http://localhost:port/odata/$metadata. Voici les métadonnées du point de terminaison présentés dans ce tutoriel.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:05:52 GMT
Content-Length: 1086

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
  <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <Schema Namespace="ProductService.Models" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityType Name="Product">
        <Key>
          <PropertyRef Name="ID" />
        </Key>
        <Property Name="ID" Type="Edm.Int32" Nullable="false" />
        <Property Name="Name" Type="Edm.String" />
        <Property Name="Price" Type="Edm.Decimal" Nullable="false" />
        <Property Name="Category" Type="Edm.String" />
      </EntityType>
    </Schema>
    <Schema Namespace="Default" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
        <EntitySet Name="Products" EntityType="ProductService.Models.Product" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

Jeu d'entités

Pour obtenir le jeu d’entités Products, envoyez une requête GET à http://localhost:port/odata/Products.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:01:31 GMT
Content-Length: 459

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products","value":[
    {
      "ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
    },{
      "ID":2,"Name":"Socks","Price":"5.00","Category":"Apparel"
    },{
      "ID":3,"Name":"Scarf","Price":"12.00","Category":"Apparel"
    },{
      "ID":4,"Name":"Yo-yo","Price":"4.95","Category":"Toys"
    },{
      "ID":5,"Name":"Puzzle","Price":"8.00","Category":"Toys"
    }
  ]
}

Entité

Pour obtenir un produit individuel, envoyez une demande GET à http://localhost:port/odata/Products(1), où « 1 » est l’ID de produit.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:04:29 GMT
Content-Length: 140

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element","ID":1,
      "Name":"Hat","Price":"15.00","Category":"Apparel"
}

Formats de sérialisation OData

OData prend en charge plusieurs formats de sérialisation :

  • Atom Pub (XML)
  • JSON « light » (introduit dans OData v3)
  • JSON « détaillé » (OData v2)

Par défaut, l’API web utilise le format « light » AtomPubJSON.

Pour obtenir le format AtomPub, définissez l’en-tête Accept sur « application/atom+xml ». Voici un exemple de corps de réponse :

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://localhost:60868/odata" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
  <id>http://localhost:60868/odata/Products(1)</id>
  <category term="ProductService.Models.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <link rel="edit" href="http://localhost:60868/odata/Products(1)" />
  <link rel="self" href="http://localhost:60868/odata/Products(1)" />
  <title />
  <updated>2013-09-23T23:42:11Z</updated>
  <author>
    <name />
  </author>
  <content type="application/xml">
    <m:properties>
      <d:ID m:type="Edm.Int32">1</d:ID>
      <d:Name>Hat</d:Name>
      <d:Price m:type="Edm.Decimal">15.00</d:Price>
      <d:Category>Apparel</d:Category>
    </m:properties>
  </content>
</entry>

Vous pouvez voir un inconvénient évident du format Atom : il est beaucoup plus détaillé que la lumière JSON. Toutefois, si vous avez un client qui comprend AtomPub, le client peut préférer ce format à JSON.

Voici la version légère JSON de la même entité :

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element",
  "ID":1,
  "Name":"Hat",
  "Price":"15.00",
  "Category":"Apparel"
}

Le format léger JSON a été introduit dans la version 3 du protocole OData. Pour la compatibilité descendante, un client peut demander l’ancien format JSON « détaillé ». Pour demander un code JSON détaillé, définissez l’en-tête Accept sur application/json;odata=verbose. Voici la version détaillée :

{
  "d":{
    "__metadata":{
      "id":"http://localhost:18285/odata/Products(1)",
      "uri":"http://localhost:18285/odata/Products(1)",
      "type":"ProductService.Models.Product"
    },"ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
  }
}

Ce format transmet davantage de métadonnées dans le corps de la réponse, ce qui peut ajouter une surcharge considérable sur l’ensemble d’une session. En outre, il ajoute un niveau d’indirection en encapsulant l’objet dans une propriété nommée « d ».

Étapes suivantes