Condividi tramite


Il presente articolo è stato tradotto automaticamente.

ASP.NET

Creazione di API Web ipermedia con le API Web ASP.NET

Pablo Cibraro

Scarica il codice di esempio

Ipermedia, meglio conosciuto come ipermedia come motore di applicazione dello stato (HATEOAS) — è uno dei principali vincoli di REST Representational State Transfer ().L'idea è che gli artefatti di ipermedia, come link o moduli, possono essere utilizzati per descrivere come i clienti possono interagire con un set di servizi HTTP.Questo è diventato rapidamente un concetto interessante per lo sviluppo evolutivo progettazione API.Questo non è diverso da come di solito interagiamo con il Web.In genere ricordiamo un URL o un singolo punto di ingresso per la Home page di un sito Web e poi passare attraverso le diverse sezioni del sito usando i link.Facciamo anche uso di forme, che sono dotati di un'azione predefinita o URL per inviare i dati che il sito potrebbe essere necessario eseguire alcune azioni.

Gli sviluppatori hanno la tendenza a fornire descrizioni statiche di tutti i metodi supportati in un servizio, che vanno dai contratti formali come WSDL Web Services Description Language () in servizi SOAP semplice documentazione in non-ipermedia Web API.Il problema principale di questo è che una descrizione statica API coppie pesantemente i client al server.In poche parole, inibisce l'evolvibilità, come qualsiasi cambiamento nella descrizione dell'API può rompere tutti i clienti esistenti.

Questo non era un problema per un nell'impresa, dove il numero di applicazioni client potrebbe essere controllato e noto in anticipo.Tuttavia, quando aumenta in modo esponenziale il numero di potenziali clienti — come è il caso di oggi, con migliaia di applicazioni di terze parti in esecuzione su più dispositivi — è una cattiva idea.Ancora, semplicemente muovendo dal sapone ai servizi HTTP non è alcuna garanzia che il problema sarà risolto.Se c'è qualche conoscenza sul client per elaborazione URL, ad esempio, il problema esiste ancora, anche senza alcun contratto esplicito come WSDL.Ipermedia è ciò che offre la possibilità di proteggere i clienti da eventuali cambiamenti di server.

Il workflow di stato applicazione, che determina che cosa può fare il cliente successivo, dovrebbe trovarsi anche sul lato server.Si supponga che un'azione in una risorsa è disponibile solo per un determinato stato; quella logica dovrebbe risiedere in qualsiasi client API possibile?Sicuramente non.Il server deve sempre mandato cosa si può fare con una risorsa.Ad esempio, se viene annullato un ordine di acquisto (OPA), l'applicazione client non dovrebbe essere consentito inviare PO, che significa un link o un modulo per inviare il PO non dovrebbe essere disponibile nella risposta inviata al client.

Ipermedia per il salvataggio

Collegamento è sempre stato una componente chiave dell'architettura REST.Naturalmente, i collegamenti sono familiare in contesti dell'interfaccia utente, ad esempio i browser; si consideri, ad esempio, un link "Vedi dettagli" per ottenere i dettagli di un determinato prodotto in un catalogo.Ma per quanto riguarda gli scenari computer-to-computer dove non non c'è nessuna interazione dell'interfaccia utente o utente?L'idea è che è possibile utilizzare gli artefatti ipermedia in questi scenari così.

Con questo nuovo approccio, il server non restituisce solo dati.Restituisce dati e ipermediali artefatti.Gli artefatti di ipermedia dare al client un modo per determinare il set di azioni che possono essere eseguite in un dato punto basato sullo stato del flusso di lavoro applicazione server disponibile.

Questa è una zona che in genere differenzia un normale Web API da una API RESTful, ma ci sono altri vincoli che si applicano anche, così discutendo se un'API RESTful o non probabilmente non ha senso nella maggior parte dei casi.Ciò che conta è che l'API utilizza correttamente HTTP come protocollo di applicazione e sfrutta l'ipermedia quando possibile.Abilitando ipermedia, è possibile creare API self-discoverable.Questa non è una scusa per non fornire documentazione, ma le API sono più flessibili in termini di aggiornabilità.

Quali manufatti ipermedia sono disponibili è determinata principalmente dai tipi di media scelti.Molti dei tipi di media che usiamo oggi per costruire un Web API, ad esempio JSON o XML, non hanno un concetto integrato per rappresentare i collegamenti o forme, come HTML.È possibile sfruttare tali tipi di supporto mediante la definizione di un modo per esprimere ipermedia, ma questo richiede che clienti a capire come la semantica di ipermedia vengono definita sopra quelli.Al contrario, tipi di media come XHTML (application/xhtml + xml) o ATOM (application/atom + xml) già supportano alcuni di questi iper­artefatti multimediali quali collegamenti o forme.

Nel caso di HTML, un link è costituito da tre componenti: un attributo "href" che punta a un URL, digitare un attributo "rel" per descrivere come il link si riferisce alla risorsa attuale e un attributo facoltativo "tipo" per la specifica media prevista.Ad esempio, se si desidera esporre un elenco di prodotti in un catalogo utilizzando XHTML, il carico utile risorsa potrebbe essere simile ciò che viene mostrato Figura 1.

Figura 1 utilizzando XHTML per esporre un elenco di prodotti

<div id="products">
  <ul class="all">
    <li>
      <span class="product-id">1</span>
      <span class="product-name">Product 1</span>
      <span class="product-price">5.34</span>
      <a rel="add-cart" href="/cart" type="application/xml"/>
    </li>
    <li>
      <span class="product-id">2</span>
      <span class="product-name">Product 2</span>
      <span class="product-price">10</span>
      <a rel="add-cart" href="/cart" type="application/xml"/>
    </li>
  </ul>
</div>

In questo esempio, il catalogo dei prodotti è rappresentato con elementi HTML standard, ma ho usato XHTML perché è molto più facile da analizzare con qualsiasi libreria XML esistente. Inoltre, come parte del payload, un ancoraggio (a) elemento è stato incluso, che rappresenta un collegamento per aggiungere l'articolo al carrello utente corrente. Guardando il link, un client può dedurre l'utilizzo tramite l'attributo rel (aggiungere un nuovo elemento) e utilizzare l'href per eseguire un'operazione su tale risorsa (/ carrello). È importante notare che i link sono generati dal server basato sul suo flusso di lavoro aziendale, quindi il client non è necessario codificare qualsiasi URL o dedurre qualsiasi regola. Questo offre anche nuove opportunità di modificare il flusso di lavoro durante il runtime senza interessare a tutti i clienti esistenti. Se uno qualsiasi dei prodotti offerti nel catalogo sono esauriti, il server può omettere semplicemente il link per aggiungere il prodotto al carrello. Dal punto di vista del cliente, il link non è disponibile, così il prodotto non può essere ordinato. Regole più complesse relative al flusso di lavoro potrebbe applicare sul lato server che il client è completamente ignaro di ciò, l'unica cosa che conta è che il link non è presente. Grazie ai collegamenti e ipermedia, il cliente ha stato disaccoppiato dal flusso di lavoro di business sul lato server.

Inoltre, l'evolvibilità di un disegno di API può essere migliorata con ipermedia e collegamenti. Come si evolve il flusso di lavoro aziendale sul server, può offrire ulteriori link per nuove funzionalità. Nel nostro esempio di catalogo del prodotto, il server potrebbe includere un nuovo link per la marcatura di un prodotto come un favorito, come questo:

<li>
  <span class="product-id">1</span>
  <span class="product-name">Product 1</span>
  <span class="product-price">5.34</span>
  <a rel="add-cart" href="/cart/1" type="application/xml"/>
  <a rel="favorite" href="/product_favorite/1" 
     type="application/xml"/>
</li>

Mentre i client esistenti potrebbero ignorare quel link e rimangono inalterati da questa nuova funzionalità, i clienti più recenti possono iniziare ad usarlo subito. In questo modo, non sarebbe pazzo a pensare di avere un ingresso singolo punto o radice URL per il tuo Web API che contiene collegamenti per scoprire il resto delle funzionalità. Ad esempio, si potrebbe avere un singolo URL "/ shopping_cart" che restituisce la rappresentazione HTML seguente:

<div class="root">
  <a rel="products" href="/products"/>
  <a rel="cart" href="/cart"/>
  <a rel="favorites" href="/product_favorite"/>
</div>

Funzionalità analoghe si trova anche in servizi OData, che espongono un documento singolo servizio l'URL principale con tutti i set di risorse supportati e link per ottenere i dati associati ad essi.

Link rappresentano un ottimo modo per collegare client e server, ma c'è un evidente problema con loro. Nell'esempio precedente con il catalogo prodotti, un link in HTML offre solo il rel, gli attributi href e tipo, che implica alcune conoscenze di out-of-band su cosa fare con quel URL espressa nell'attributo href. Il client utilizzi un HTTP POST o GET HTTP? Se utilizza un POST, quali dati deve il client includono nel corpo della richiesta? Mentre tutto ciò che potrebbe essere conoscenza documentata da qualche parte, non sarebbe bello se i clienti effettivamente potrebbero scoprire che la funzionalità? Per tutte queste domande, utilizzando i moduli HTML è la risposta che fa un sacco di senso.

Forme in azione

Quando si interagisce con il Web utilizzando un browser, le azioni sono in genere rappresentate con forme. Nell'esempio di catalogo prodotto, premendo Aggiungi al carrello implica un HTTP GET inviati al server di restituire un modulo HTML che può essere utilizzato per aggiungere il prodotto al carrello. Tale forma potrebbe contenere un attributo "action" con un URL, un attributo "method" che rappresenta il metodo HTTP, e alcuni input campi che potrebbero richiedere l'input dall'utente, come pure alcune istruzioni leggibili per andare avanti.

Si può fare lo stesso per uno scenario di machine-to-machine. Piuttosto che un essere umano interagisce con un modulo, si potrebbe avere un'applicazione in esecuzione JavaScript o c#. Nel catalogo prodotti, un HTTP GET per il link "Aggiungi-carrello" per il primo prodotto sarebbe recuperare il modulo di seguito rappresentato in XHTML:

<form action="/cart" method="POST">
  <input type="hidden" id="product-id">1</input>
  <input type="hidden" id="product-price">5.34</input>
  <input type="hidden" id="product-quantity" class="required">1</input>
  <input type="hidden" id="___forgeryToken">XXXXXXXX</input>
</form>

L'applicazione client è ora stato disaccoppiato da alcuni dettagli relativi a aggiungendo il prodotto al carrello. Ha solo bisogno di inviare questo modulo usando un HTTP POST per l'URL specificato nell'attributo action. Il server può anche includere informazioni aggiuntive nella forma — per esempio, un token di falsificazione per evitare attacchi di cross-site request forgery (CSRF) o di firmare i dati che sono prepopolati per il server.

Questo modello permette qualsiasi API Web di evolversi liberamente offrendo nuovi moduli basati su diversi fattori come ad esempio le autorizzazioni utente o la versione del client vuole utilizzare.

Ipermedia per XML e JSON?

Come accennato in precedenza, i tipi di supporto generico per XML (applicazione /­xml) e JSON (applicazione/json) non hanno un supporto incorporato per collegamenti ipermediali o forme. Mentre è possibile estendere i tipi di media con concetti di dominio-specifici come "application/vnd-shoppingcart + xml", questo richiede nuovi clienti a capire tutta la semantica definita in quel nuovo tipo (e probabilmente sarebbe anche generare una proliferazione dei tipi di media) quindi non è generalmente considerata una buona idea.

Per questo motivo, è stato proposto un nuovo tipo di media che estende il JSON e XML con collegamento semantica è chiamato Hypertext Application Language (HAL). Il progetto, che definisce semplicemente un modo standard per esprimere i collegamenti ipertestuali e le risorse incorporate (dati) utilizzando XML e JSON, è disponibile presso stateless.co/hal_specification.html. Il tipo di supporto HAL definisce una risorsa che contiene un insieme di proprietà, un insieme di collegamenti e un set di risorse incorporate, come mostrato Figura 2.

The HAL Media Type
Nella figura 2 il tipo di supporto HAL

Figura 3 Mostra un esempio di come un catalogo prodotti apparirebbe in HAL utilizzando rappresentazioni sia il XML e JSON. Figura 4 è la rappresentazione JSON per la risorsa del campione.

Figura 3 il catalogo prodotti di HAL

<resource href="/products">
  <link rel="next" href="/products?page=2" />
  <link rel="find" href="/products{?id}" templated="true" />
  <resource rel="product" href="/products/1">
    <link rel="add-cart" href="/cart/" />
    <name>Product 1</name>
    <price>5.34</price>
  </resource>
  <resource rel="product" href="/products/2">
    <link rel="add-cart" href="/cart/" />
    <name>Product 2</name>
    <price>10</price>
  </resource>
</resource>

Figura 4 la rappresentazione JSON per la risorsa del campione

{
  "_links": {
    "self": { "href": "/products" },
    "next": { "href": "/products?page=2" },
    "find": { "href": "/products{?id}", "templated": true }
  },
  "_embedded": {
    "products": [{
      "_links": {
        "self": { "href": "/products/1" },
        "add-cart": { "href": "/cart/" },
      },
      "name": "Product 1",
      "price": 5.34,
    },{
      "_links": {
        "self": { "href": "/products/2" },
        "add-cart": { "href": "/cart/" }
      },
      "name": "Product 2",
      "price": 10
    }]
  }
}

Supporto ipermedia in ASP.NET Web API

Finora ho discusso alcuni della teoria dietro ipermediali nella progettazione di Web API. Ora Let's vedere come tale teoria può essere implementato in realtà nel mondo reale utilizzando ASP.NET Web API, con tutto l'estensibilità punti e caratteristiche di questo quadro, fornisce.

A un livello di base, ASP.NET Web API supporta l'idea di formattatori. Un'implementazione del formattatore sa come trattare con un tipo di supporto specifico e come serializzare o deserializzare esso in calcestruzzo tipi .NET. In passato, il supporto per nuovi tipi di media era molto limitato in ASP.NET MVC. Solo HTML e JSON sono stati trattati come cittadini di prima classe e pienamente supportato attraverso l'intero stack. Inoltre, non non c'era nessun modello coerente per supportare la negoziazione dei contenuti. Si potrebbero sostenere differenti formati di tipo per i messaggi di risposta da fornire implementazioni personalizzate di ActionResult, ma non era chiaro come potrebbe essere introdotto un nuovo tipo di supporto per la deserializzazione di messaggi di richiesta. In genere questo è stato risolto sfruttando l'infrastruttura di associazione del modello con nuovi leganti modello o fornitori di valore. Fortunatamente, questa discrepanza è stata risolta in ASP.NET Web API con l'introduzione di formattatori.

Ogni formattatore deriva dalla classe base System.Net.Http.Formatting.MediaTypeFormatter ed esegue l'override del metodo CanReadType/ReadFromStreamAsync per sostenere la deserializzazione e il metodo CanWriteType/WriteToStreamAsync per il supporto di serializzazione di .NET i tipi in un formato di tipo data media.

Figura 5 viene illustrata la definizione della classe MediaTypeFormatter.

Figura 5 la classe MediaTypeFormatter

public abstract class MediaTypeFormatter
{
  public Collection<Encoding> SupportedEncodings { get; }
  public Collection<MediaTypeHeaderValue> SupportedMediaTypes { get; }
  public abstract bool CanReadType(Type type);
  public abstract bool CanWriteType(Type type);
  public virtual Task<object> ReadFromStreamAsync(Type type, 
    Stream readStream,
    HttpContent content, IFormatterLogger formatterLogger);
  public virtual Task WriteToStreamAsync(Type type, object value,
    Stream writeStream, HttpContent content, 
    TransportContext transportContext);
}

I formattatori gioca un ruolo molto importante in ASP.NET Web API nel sostenere la negoziazione dei contenuti, come il quadro può ora scegliere il formattatore corretto sulla base dei valori ricevuti nelle intestazioni del messaggio di richiesta "Accetta" e "Content-Type".

I metodi ReadFromStreamAsync e WriteToStreamAsync si basano su Task Parallel Library (TPL) per fare il lavoro asincrono, quindi restituiscono un'istanza dell'attività. Nel caso in cui si vuole esplicitamente fare il formattatore lavoro di implementazione in modo sincrono, la classe base, BufferedMediaTypeFormatter, lo fa per te internamente. Questa classe base fornisce due metodi che è possibile eseguire l'override in un'implementazione, SaveToStream e ReadFromStream, che sono le versioni sincrone di SaveToStreamAsync e ReadFromStreamAsync.

Lo sviluppo di un MediaTypeFormatter per HAL

HAL utilizza la semantica specifici per rappresentare le risorse e collegamenti, quindi si può usare qualsiasi modello in un'applicazione Web API. Per questo motivo, una classe di base per rappresentare una risorsa e un altro per un insieme di risorse vengono utilizzati per rendere molto più semplice l'implementazione del formattatore:

public abstract class LinkedResource
{
  public List<Link> Links { get; set; }
  public string HRef { get; set; }
}
public abstract class LinkedResourceCollection<T> : LinkedResource,
  ICollection<T> where T : LinkedResource
{
  // Rest of the collection implementation
}

Le classi del modello reale che utilizzeranno i controllori Web API possono derivare da queste due classi di base. Ad esempio, un prodotto o un insieme di prodotti può essere implementato come segue:

public class Product : LinkedResource
{
  public int Id { get; set; }
  public string Name { get; set; }
  public decimal UnitPrice { get; set; }
}
...
public class Products : LinkedResourceCollection<Product>
{
}

Ora, con un modo standard per definire modelli HAL, è il momento di attuare il formattatore. Il modo più semplice per iniziare una nuova implementazione del formattatore consiste nel derivare da sia la classe di base MediaTypeFormatter o dalla classe base BufferedMediaTypeFormatter. L'esempio in Figura 6 utilizza la classe seconda base.

Figura 6 la classe di Base BufferedMediaTypeFormatter

public class HalXmlMediaTypeFormatter : BufferedMediaTypeFormatter
{
  public HalXmlMediaTypeFormatter()
    : base()
  {
    this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(
      "application/hal+xml"));
  }
  public override bool CanReadType(Type type)
  {
    return type.BaseType == typeof(LinkedResource) ||
      type.BaseType.GetGenericTypeDefinition() ==
        typeof(LinkedResourceCollection<>);
  }
  public override bool CanWriteType(Type type)
  {
    return type.BaseType == typeof(LinkedResource) ||
     type.BaseType.GetGenericTypeDefinition() ==
       typeof(LinkedResourceCollection<>);
  }
  ...
}

Il codice prima definisce nel costruttore i tipi di media supportati per questa implementazione (applicazione/hal + xml") ed esegue l'override dei metodi CanReadType e CanWriteType per specificare i tipi supportati di .NET, che devono derivare da collegato­risorsa o LinkedResourceCollection. Perché è stato definito nel costruttore, questa implementazione supporta solo la variante XML di HAL. Formattatore un altro facoltativamente potrebbe essere implementato per supportare la variante JSON.

Il vero lavoro viene fatto nei metodi WriteToStream e ReadFromStream, mostrati Figura 7, che utilizzerà un XmlWriter e XmlReader, rispettivamente, per scrivere e leggere un oggetto dentro e fuori un flusso.

Figura 7 il WriteToStream e metodi ReadFromStream

public override void WriteToStream(Type type, object value,
  System.IO.Stream writeStream, System.Net.Http.HttpContent content)
{
  var encoding = base.SelectCharacterEncoding(content.Headers);
  var settings = new XmlWriterSettings();
  settings.Encoding = encoding;
  var writer = XmlWriter.Create(writeStream, settings);
  var resource = (LinkedResource)value;
  if (resource is IEnumerable)
  {
    writer.WriteStartElement("resource");
    writer.WriteAttributeString("href", resource.HRef);
    foreach (LinkedResource innerResource in (IEnumerable)resource)
    {
      // Serializes the resource state and links recursively
      SerializeInnerResource(writer, innerResource);
    }
    writer.WriteEndElement();
  }
  else
  {
    // Serializes a single linked resource
    SerializeInnerResource(writer, resource);
  }
  writer.Flush();
  writer.Close();
}
public override object ReadFromStream(Type type,
  System.IO.Stream readStream, System.Net.Http.HttpContent content,
  IFormatterLogger formatterLogger)
{
  if (type != typeof(LinkedResource))
    throw new ArgumentException(
      "Only the LinkedResource type is supported", "type");
  var value = (LinkedResource)Activator.CreateInstance(type);
  var reader = XmlReader.Create(readStream);
  if (value is IEnumerable)
  {
    var collection = (ILinkedResourceCollection)value;
    reader.ReadStartElement("resource");
    value.HRef = reader.GetAttribute("href");
    var innerType = type.BaseType.GetGenericArguments().First();
    while (reader.Read() && reader.LocalName == "resource")
    {
      // Deserializes a linked resource recursively
      var innerResource = DeserializeInnerResource(reader, innerType);
      collection.Add(innerResource);
    }
  }
  else
  {
    // Deserializes a linked resource recursively
    value = DeserializeInnerResource(reader, type);
  }
  reader.Close();
  return value;
}

L'ultimo passo è quello di configurare l'implementazione del formattatore come parte dell'host Web API. Questo passaggio può essere realizzato in quasi allo stesso modo come in ASP o ASP.NET Web API indipendente, con una sola differenza nell'implementazione del HttpConfiguration necessaria. Mentre il servizio indipendente utilizza un'istanza di HttpSelfHostConfiguration, ASP.NET in genere utilizza l'istanza di HttpConfiguration disponibile globalmente in System.Web.Http.GlobalConfiguration.Configuration. La classe HttpConfiguration fornisce un insieme di formattatori in cui è possibile inserire la propria implementazione del formattatore. Ecco come fare per ASP.NET:

protected void Application_Start()
{
  Register(GlobalConfiguration.Configuration);
}
public static void Register(HttpConfiguration config)
{
  config.Formatters.Add(new HalXmlMediaTypeFormatter());
}

Una volta che il formattatore è configurato nella pipeline di ASP.NET Web API, qualsiasi controller può semplicemente restituire una classe modello derivata da LinkedResource ad essere serializzato dal formattatore mediante HAL. Per esempio il catalogo prodotto, il prodotto e l'insieme dei prodotti che rappresenta il catalogo possono essere derivati dal LinkedResource e LinkedResourceCollection, rispettivamente:

public class Product : LinkedResource
{
  public int Id { get; set; }
  public string Name { get; set; }
  public decimal UnitPrice { get; set; }
}
public class Products : LinkedResourceCollection<Product>
{
}

Il controller ProductCatalogController, che gestisce tutte le richieste per la risorsa del catalogo prodotti, ora può restituire istanze di prodotto e di prodotti come mostrato Figura 8 per il metodo Get.

Figura 8 la classe ProductCatalogController

public class ProductCatalogController : ApiController
{
  public static Products Products = new Products
  {
    new Product
    {
      Id = 1,
      Name = "Product 1",
      UnitPrice = 5.34M,
      Links = new List<Link>
      {
        new Link { Rel = "add-cart", HRef = "/api/cart" },
        new Link { Rel = "self", HRef = "/api/products/1" }
      }
    },
    new Product
    {
      Id = 2,
      Name = "Product 2",
      UnitPrice = 10,
      Links = new List<Link>
      {
        new Link { Rel = "add-cart", HRef = "/cart" },
        new Link { Rel = "self", HRef = "/api/products/2" }
      }
    }
  };
  public Products Get()
  {
    return Products;           
  }
}

In questo esempio viene utilizzato il formato HAL, ma è possibile anche utilizzare un approccio simile per costruire un formattatore che utilizza modelli e rasoio per la serializzazione di modelli in XHTML. Troverete un'implementazione concreta di un MediaTypeFormatter per rasoio in RestBugs, un'applicazione di esempio creata da Howard Dierking per dimostrare come ASP.NET Web API può essere utilizzato per creare ipermedia Web API, a github.com/howarddierking/RestBugs.

I formattatori rendono facile estendere il vostro Web API con nuovi tipi di supporto.

Migliore collegamento supporto nei controllori Web API

Qualcosa è sicuramente sbagliato con il precedente ProductCatalog­esempio di Controller. Tutti i link sono stati hardcoded, che potrebbe causare un sacco di mal di testa se gli itinerari cambiano spesso. La buona notizia è che il framework fornisce una classe helper denominata System.Web.Http.Routing.UrlHelper per l'inferenza automaticamente i link dalla tabella di routing. Un'istanza di questa classe è disponibile nella classe base ApiController attraverso la proprietà Url, quindi può essere utilizzato facilmente in qualsiasi metodo del controller. Questo è quello che sembra la definizione della classe UrlHelper:

public class UrlHelper
{
  public string Link(string routeName,
    IDictionary<string, object> routeValues);
  public string Link(string routeName, object routeValues);
  public string Route(string routeName,
    IDictionary<string, object> routeValues);
  public string Route(string routeName, object routeValues);
}

L'itinerario i metodi restituiscono l'URL relativo per un determinato percorso (ad esempio, /products/1), e i metodi di collegamento restituiscono l'URL assoluto, quale è quella che può essere utilizzato nei modelli per evitare qualsiasi hardcoding. Il metodo di collegamento riceve due argomenti: il nome di percorso e i valori di comporre l'URL.

Figura 9 Mostra come, nell'esempio precedente prodotto catalogo, classe UrlHelper potrebbe essere utilizzata nel metodo Get.

Figura 9 come classe UrlHelper potrebbe essere utilizzata nel metodo Get

public Products Get()
{
  var products = GetProducts();
  foreach (var product in products)
  {
    var selfLink = new Link
    {
      Rel = "self",
      HRef = Url.Route("API Default",
        new
        {
          controller = "ProductCatalog",
          id = product.Id
        })
    };
product.Links.Add(selfLink);
if(product.IsAvailable)
{
    var addCart = new Link
    {
      Rel = "add-cart",
      HRef = Url.Route("API Default",
        new
        {
          controller = "Cart"
        })
    };
    product.Links.Add(addCart);
  }           
}
  return Products;           
}

Il link "self" per il prodotto è stato generato dal percorso predefinito utilizzando il nome del controller ProductCatalog e l'id del prodotto. Il link per aggiungere il prodotto al carrello è stato anche dal percorso predefinito, ma utilizzato invece il nome del controller Cart. Come si può vedere Figura 9, il link per aggiungere il prodotto al carrello è associato alla risposta basata sulla disponibilità del prodotto (product.IsAvailable). La logica per fornire collegamenti al client dipenderà praticamente le regole di business in genere applicate nei controllori.

Conclusioni

Ipermedia è una potente funzionalità che consente ai client e server di evolvere in modo indipendente. Tramite link o altri manufatti ipermedia come forme offerte dal server in diverse fasi, i clienti possono essere disaccoppiati con successo dal workflow server aziendali che spinge l'interazione.

Pablo Cibraro è un esperto riconosciuto a livello internazionale con più di 12 anni di esperienza nella progettazione e implementazione di grandi sistemi con tecnologie Microsoft distribuiti. Egli è un MVP di sistemi connessi. Negli ultimi nove anni Cibraro ha contribuito a numerose squadre di Microsoft sviluppare strumenti e Framework per la creazione di applicazioni orientate ai servizi con i servizi Web, Windows Communication Foundation, ASP.NET e Windows Azure. Ha Blog at weblogs.asp.net/cibrax ed è possibile seguirlo su Twitter a twitter.com/cibrax.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Daniel Roth