Creazione di un endpoint OData v3 con l'API Web 2

di Mike Wasson

Scaricare il progetto completato

Open Data Protocol (OData) è un protocollo di accesso ai dati per il Web. OData offre un modo uniforme per strutturare i dati, eseguire query sui dati e modificare il set di dati tramite operazioni CRUD (creare, leggere, aggiornare ed eliminare). OData supporta sia i formati AtomPub (XML) che JSON. OData definisce anche un modo per esporre i metadati sui dati. I client possono usare i metadati per individuare le informazioni sul tipo e le relazioni per il set di dati.

API Web ASP.NET semplifica la creazione di un endpoint OData per un set di dati. È possibile controllare esattamente quali operazioni OData supportano l'endpoint. È possibile ospitare più endpoint OData, insieme a endpoint non OData. Si ha il controllo completo sul modello di dati, sulla logica di business back-end e sul livello dati.

Versioni software usate nell'esercitazione

Il supporto OData dell'API Web è stato aggiunto nell'aggiornamento ASP.NET and Web Tools 2012.2. Questa esercitazione usa tuttavia lo scaffolding aggiunto in Visual Studio 2013.

In questa esercitazione verrà creato un semplice endpoint OData su cui i client possono eseguire query. Si creerà anche un client C# per l'endpoint. Al termine di questa esercitazione, il set successivo di esercitazioni illustra come aggiungere altre funzionalità, tra cui relazioni di entità, azioni e $expand/$select.

Creare il progetto di Visual Studio

In questa esercitazione verrà creato un endpoint OData che supporta operazioni CRUD di base. L'endpoint espone una singola risorsa, un elenco di prodotti. Le esercitazioni successive aggiungeranno altre funzionalità.

Avviare Visual Studio e selezionare Nuovo progetto nella pagina Iniziale. In alternativa, scegliere Nuovo dal menu File e quindi Progetto.

Nel riquadro Modelli selezionare Modelli installati ed espandere il nodo Visual C#. In Visual C# selezionare Web. Selezionare il modello applicazione Web ASP.NET .

Screenshot della finestra del nuovo progetto, che mostra il percorso del riquadro del modello e visualizza le indicazioni evidenziate per selezionare l'opzione Applicazione Web P punto S.

Nella finestra di dialogo Nuovo progetto ASP.NET selezionare il modello Vuoto . In "Aggiungi cartelle e riferimenti di base per...", selezionare API Web. Fare clic su OK.

Screenshot della finestra di dialogo A S P dot NET project ,che mostra le caselle di opzioni del modello ed evidenzia l'opzione 'empty'.

Aggiungere un modello di entità

Un modello è un oggetto che rappresenta i dati nell'applicazione. Per questa esercitazione è necessario un modello che rappresenta un prodotto. Il modello corrisponde al tipo di entità OData.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Modelli. Nel menu di scelta rapida selezionare Aggiungi e quindi selezionare Classe.

Screenshot della finestra di dialogo Esplora soluzioni, che mostra l'elenco di menu per ogni selezione, evidenziando ogni opzione, che conduce all'opzione della classe .

Nella finestra di dialogo Aggiungi nuovo elemento assegnare alla classe il nome "Product".

Screenshot della finestra

Nota

Per convenzione, le classi modello vengono inserite nella cartella Models. Non è necessario seguire questa convenzione nei propri progetti, ma verrà usata per questa esercitazione.

Nel file Product.cs aggiungere la definizione di classe seguente:

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

La proprietà ID sarà la chiave di entità. I client possono eseguire query sui prodotti in base all'ID. Questo campo sarà anche la chiave primaria nel database back-end.

Compilare ora il progetto. Nel passaggio successivo si userà uno scaffolding di Visual Studio che usa la reflection per trovare il tipo di prodotto.

Aggiungere un controller OData

Un controller è una classe che gestisce le richieste HTTP. Si definisce un controller separato per ogni set di entità nel servizio OData. In questa esercitazione verrà creato un singolo controller.

In Esplora soluzioni fare clic sulla cartella Controller. Selezionare Aggiungi e quindi selezionare Controller.

Screenshot della finestra esplora soluzioni, che evidenzia l'opzione controller che visualizza quindi i menu per aggiungere un controller di dati O.

Nella finestra di dialogo Aggiungi scaffolding selezionare "Web API 2 OData Controller with actions, using Entity Framework".

Screenshot della schermata

Nella finestra di dialogo Aggiungi controller assegnare al controller il nome "ProductsController". Selezionare la casella di controllo "Usa azioni del controller asincrono". Nell'elenco a discesa Modello selezionare la classe Product.

Screenshot della finestra di dialogo Aggiungi controller, visualizzazione dei campi per il nome del controller, l'elenco a discesa della classe del modello e la classe del contesto dati.

Fare clic sul pulsante Nuovo contesto dati... . Lasciare il nome predefinito per il tipo di contesto dati e fare clic su Aggiungi.

Screenshot della nuova finestra del contesto dati, che mostra un campo per

Fare clic su Aggiungi nella finestra di dialogo Aggiungi controller per aggiungere il controller.

Screenshot della finestra di dialogo Aggiungi controller, che mostra i diversi requisiti di campo, con una casella di controllo per l'uso di azioni del controller asincrono.

Nota: se viene visualizzato un messaggio di errore che indica "Si è verificato un errore durante il recupero del tipo...", assicurarsi di aver compilato il progetto di Visual Studio dopo aver aggiunto la classe Product. Lo scaffolding usa la reflection per trovare la classe .

Screenshot di Microsoft Visual Studio, che mostra un cerchio rosso

Lo scaffolding aggiunge due file di codice al progetto:

  • Products.cs definisce il controller API Web che implementa l'endpoint OData.
  • ProductServiceContext.cs fornisce metodi per eseguire query sul database sottostante usando Entity Framework.

Screenshot della finestra del progetto, che mostra il menu del servizio del prodotto e che circonda i due file appena aggiunti nei controller e nei modelli.

Aggiungere ed eseguire la route EDM

In Esplora soluzioni espandere la cartella App_Start e aprire il file denominato WebApiConfig.cs. Questa classe contiene il codice di configurazione per l'API Web. Sostituire questo codice con il seguente:

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());
        }
    }
}

Questo codice esegue due operazioni:

  • Crea un modello EDM (Entity Data Model) per l'endpoint OData.
  • Aggiunge una route per l'endpoint.

Edm è un modello astratto dei dati. L'edm viene usato per creare il documento di metadati e definire gli URI per il servizio. ODataConventionModelBuilder crea un EDM usando un set di convenzioni di denominazione predefinite EDM. Questo approccio richiede il codice minimo. Se si vuole un maggiore controllo sull'EDM, è possibile usare la classe ODataModelBuilder per creare EDM aggiungendo proprietà, chiavi e proprietà di spostamento in modo esplicito.

Il metodo EntitySet aggiunge un set di entità all'EDM:

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

La stringa "Products" definisce il nome del set di entità. Il nome del controller deve corrispondere al nome del set di entità. In questa esercitazione il set di entità è denominato "Products" e il controller è denominato ProductsController. Se si chiama il set di entità "ProductSet", si chiamerebbe il controller ProductSetController. Si noti che un endpoint può avere più set di entità. Chiamare EntitySet<T> per ogni set di entità e quindi definire un controller corrispondente.

Il metodo MapODataRoute aggiunge una route per l'endpoint OData.

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

Il primo parametro è un nome descrittivo per la route. I client del servizio non visualizzano questo nome. Il secondo parametro è il prefisso URI per l'endpoint. Dato questo codice, l'URI per il set di entità Products è http:// hostname/odata/Products. L'applicazione può avere più di un endpoint OData. Per ogni endpoint chiamare MapODataRoute e specificare un nome di route univoco e un prefisso URI univoco.

Inizializzare il database (facoltativo)

In questo passaggio si userà Entity Framework per inizializzare il database con alcuni dati di test. Questo passaggio è facoltativo, ma consente di testare immediatamente l'endpoint OData.

Dal menu Strumenti selezionare Gestione pacchetti NuGet, quindi selezionare Console di Gestione pacchetti. Nella finestra Console di gestione pacchetti immettere il comando seguente:

Enable-Migrations

In questo modo viene aggiunta una cartella denominata Migrations e un file di codice denominato Configuration.cs.

Screenshot del menu del servizio prodotto di Esplora soluzioni, che circonda la cartella appena aggiunta denominata migrazione e che mostra il file all'interno.

Aprire questo file e aggiungere il codice seguente al Configuration.Seed metodo.

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" },
    });
}

Nella finestra Console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration Initial
Update-Database

Questi comandi generano codice che crea il database e quindi esegue tale codice.

Esplorazione dell'endpoint OData

In questa sezione verrà usato il proxy di debug Web Fiddler per inviare richieste all'endpoint ed esaminare i messaggi di risposta. Ciò consente di comprendere le funzionalità di un endpoint OData.

In Visual Studio premere F5 per avviare il debug. Per impostazione predefinita, Visual Studio apre il browser a http://localhost:*port*, dove la porta è il numero di porta configurato nelle impostazioni del progetto.

È possibile modificare il numero di porta nelle impostazioni del progetto. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Proprietà. Nella finestra delle proprietà selezionare Web. Immettere il numero di porta in Url progetto.

Documento del servizio

Il documento del servizio contiene un elenco dei set di entità per l'endpoint OData. Per ottenere il documento del servizio, inviare una richiesta GET all'URI radice del servizio.

Usando Fiddler, immettere l'URI seguente nella scheda Composer : http://localhost:port/odata/, dove la porta è il numero di porta.

Screenshot della finestra del documento del servizio, che visualizza le diverse schede con la scheda 'analizzata' scelta e che mostra i dati U R L nel campo compositore.

Fare clic sul pulsante Esegui . Fiddler invia una richiesta HTTP GET all'applicazione. Verrà visualizzata la risposta nell'elenco Sessioni Web. Se tutto funziona, il codice di stato sarà 200.

Screenshot dell'elenco delle sessioni Web, che mostra il protocollo H T T P con il numero di risultato 200 e l'indirizzo e l'host U R L.

Fare doppio clic sulla risposta nell'elenco Sessioni Web per visualizzare i dettagli del messaggio di risposta nella scheda Controlli.

Screenshot della scheda controllo dell'elenco delle sessioni Web, che visualizza la risposta Intestazioni richiesta e le informazioni X M L.

Il messaggio di risposta HTTP non elaborato dovrebbe essere simile al seguente:

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>

Per impostazione predefinita, l'API Web restituisce il documento del servizio in formato AtomPub. Per richiedere JSON, aggiungere l'intestazione seguente alla richiesta HTTP:

Accept: application/json

Screenshot della finestra sessioni Web, che mostra la risposta dalla sezione Intestazioni richiesta E circling dove scrivere la richiesta j son.

La risposta HTTP contiene ora un payload 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"
    }
  ]
}

Documento metadati del servizio

Il documento dei metadati del servizio descrive il modello di dati del servizio usando un linguaggio XML denominato Linguaggio di definizione dello schema concettuale (CSDL). Il documento dei metadati mostra la struttura dei dati nel servizio e può essere usato per generare codice client.

Per ottenere il documento dei metadati, inviare una richiesta GET a http://localhost:port/odata/$metadata. Ecco i metadati per l'endpoint illustrato in questa esercitazione.

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>

Set di entità

Per ottenere il set di entità Products, inviare una richiesta GET a 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à

Per ottenere un singolo prodotto, inviare una richiesta GET a http://localhost:port/odata/Products(1), dove "1" è l'ID prodotto.

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"
}

Formati di serializzazione OData

OData supporta diversi formati di serializzazione:

  • Pub Atom (XML)
  • JSON "light" (introdotto in OData v3)
  • JSON "verbose" (OData v2)

Per impostazione predefinita, l'API Web usa il formato "light" AtomPubJSON.

Per ottenere il formato AtomPub, impostare l'intestazione Accept su "application/atom+xml". Di seguito è riportato il corpo di una risposta di esempio:

<?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>

È possibile vedere uno svantaggio evidente del formato Atom: è molto più dettagliato rispetto alla luce JSON. Tuttavia, se si dispone di un client che riconosce AtomPub, il client potrebbe preferire tale formato su JSON.

Ecco la versione di luce JSON della stessa entità:

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

Il formato di luce JSON è stato introdotto nella versione 3 del protocollo OData. Per la compatibilità con le versioni precedenti, un client può richiedere il formato JSON "dettagliato" meno recente. Per richiedere il codice JSON dettagliato, impostare l'intestazione Accept su application/json;odata=verbose. Ecco la versione dettagliata:

{
  "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"
  }
}

Questo formato trasmette più metadati nel corpo della risposta, che può aggiungere un sovraccarico considerevole su un'intera sessione. Aggiunge inoltre un livello di indirettità eseguendo il wrapping dell'oggetto in una proprietà denominata "d".

Passaggi successivi