Condividi tramite


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 (creazione, lettura, aggiornamento ed eliminazione). 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.

ASP.NET'API Web semplifica la creazione di un endpoint OData per un set di dati. È possibile controllare esattamente le operazioni OData supportate dall'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 in ASP.NET e nell'aggiornamento degli strumenti Web 2012.2. Tuttavia, questa esercitazione usa lo scaffolding aggiunto in Visual Studio 2013.

In questa esercitazione si creerà un semplice endpoint OData su cui i client possono eseguire query. Si creerà anche un client C# per l'endpoint. Dopo aver completato 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 si creerà un endpoint OData che supporta operazioni CRUD di base. L'endpoint esporrà 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 di applicazione Web di ASP.NET.

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

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 delle 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. Dal menu di scelta rapida selezionare Aggiungi e quindi selezionare Classe.

Screenshot della finestra di dialogo Esplora Soluzioni, che mostra l'elenco del menu mentre evidenzia ciascuna selezione, fino ad arrivare all'opzione per la classe.

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

Screenshot della finestra

Annotazioni

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. Nella fase successiva useremo lo scaffolding di Visual Studio che utilizza 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 con il pulsante destro del mouse sulla cartella Controllers. Selezionare Aggiungi e quindi Controller.

Screenshot della finestra dell'esplora soluzioni, che evidenzia l'opzione del controller e quindi visualizza i menu per aggiungere un controller OData.

Nella finestra di dialogo Aggiungi struttura, selezionare "Web API 2 OData Controller con azioni, utilizzando 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, che visualizza i campi per il nome del controller, l'elenco a discesa della classe del modello e della classe 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 dei campi, con una casella di controllo per usare le azioni del controller asincrone.

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

Screenshot di Microsoft Visual Studio, che mostra una

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 prodotto e che circonda i due file appena aggiunti nei controller e nei modelli.

Aggiungere EDM e Route

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 codice 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 fa due cose:

  • Crea un entity data model (EDM) per l'endpoint OData.
  • Aggiunge una route per l'endpoint.

Un modello 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 minor codice. Se si vuole un maggiore controllo sull'EDM, è possibile usare la classe ODataModelBuilder per creare EDM aggiungendo in modo esplicito proprietà, chiavi e proprietà di spostamento.

Il metodo EntitySet aggiunge un set di entità a 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 denomini il set di entità "ProductSet", denomineresti 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 il percorso. I clienti del tuo 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 eseguire il seeding del database con alcuni dati di test. Questo passaggio è facoltativo, ma consente di testare immediatamente l'endpoint OData.

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

Enable-Migrations

Viene aggiunta una cartella denominata Migrations e un file di codice denominato Configuration.cs.

Screenshot del menu del servizio del prodotto di Esplora soluzioni, che circonda la cartella appena aggiunta denominata migrazioni e mostra il file al suo 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 utilizzeremo il Fiddler Web Debugging Proxy per inviare richieste all'endpoint ed esaminare i messaggi di risposta. Ciò consentirà di comprendere le funzionalità di un endpoint OData.

In Visual Studio premere F5 per avviare il debug. Per impostazione predefinita, Visual Studio apre il tuo browser a http://localhost:*port*, dove porta è il numero della porta configurata 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 nella sezione Url progetto.

Documento di servizio

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

Usando Fiddler, immettere l'URI seguente nella scheda Composer: http://localhost:port/odata/, dove porta si riferisce al numero di porta.

Screenshot della finestra del documento di servizio, che mostra le diverse schede con la scheda

Fare clic sul pulsante Esegui . Fiddler invia una richiesta HTTP GET all'applicazione. La risposta dovrebbe essere visualizzata 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 Inspectors .Double-click the response in the Web Sessions list to see the details of the response message in the Inspectors tab.

Screenshot della scheda di ispezione dell'elenco delle sessioni web, che mostra la risposta delle intestazioni della richiesta e le informazioni XML.

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 delle sessioni web, che mostra la risposta dall'API nella sezione Intestazioni della richiesta e che evidenzia dove scrivere la richiesta JSON.

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 dei metadati del servizio

Il documento dei metadati del servizio descrive il modello di dati del servizio, usando un linguaggio XML denominato CsDL (Conceptual Schema Definition Language). Il documento di metadati mostra la struttura dei dati nel servizio e può essere usato per generare codice client.

Per ottenere il documento di 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:

  • Atom Pub (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". Ecco un esempio di corpo della risposta:

<?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 ovvio del formato Atom: è molto più verboso rispetto al JSON leggero. Tuttavia, se si dispone di un client che riconosce AtomPub, il client potrebbe preferire tale formato rispetto a JSON.

Ecco la versione light JSON della stessa entità:

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

Il formato chiaro JSON è stato introdotto nella versione 3 del protocollo OData. Per garantire la compatibilità con le versioni precedenti, un client può richiedere il formato JSON "dettagliato" precedente. Per richiedere 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 fornisce più metadati nel corpo della risposta, che può comportare un sovraccarico notevole per un'intera sessione. Aggiunge inoltre un livello di indirezione incapsulando l'oggetto in una proprietà denominata "d".

Passaggi successivi