Création d’un point de terminaison OData v3 avec l’API web 2
par Mike Wasson
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
- Visual Studio 2013
- API web 2
- OData version 3
- Entity Framework 6
- Proxy de débogage web Fiddler (facultatif)
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
- Ajouter un modèle d’entité
- Ajouter un contrôleur OData
- Ajouter l’EDM et l’itinéraire
- Amorçage de la base de données (facultatif)
- Exploration du point de terminaison OData
- Formats de sérialisation OData
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 .
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.
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.
Dans la boîte de dialogue Ajouter un nouvel élément, nommez la classe « Product ».
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.
Dans la boîte de dialogue Ajouter une structure , sélectionnez « Contrôleur OData API Web 2 avec actions, à l’aide d’Entity Framework ».
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.
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.
Cliquez sur Ajouter dans la boîte de dialogue Ajouter un contrôleur pour ajouter le contrôleur.
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 .
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.
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.
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.
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.
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.
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
À 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 ».