[WebCast] ASP.NET MVC para desarrolloweb

Muy buenas!!! El 14 de Marzo voy a dejar de cambiar pañales durante un par de horas y voy a realizar un webcast para la gente de desarrolloweb hablando sobre ASP.NET MVC 3 (no, no vamos a comentar nada sobre la Beta 4 ya que eso daría para otro webcast).

La intención de este webcast es presentar ASP.NET MVC y está especialmente destinado a todos aquellos que no conozcan nada del framework, incluyendo a todos aquellos que desarrollan para web en tecnologías no microsoft (PHP, Java, Ruby on Rails, …). Vamos a ver el framework, las ideas que hay detrás de él y daremos un repaso rápido a sus capacidades. La duración del webcast será entre una hora – hora y pico y luego… preguntas 🙂

Uno de los motivos para realizar este webcast es que estoy colaborando con la gente de desarrolloweb en un manual de ASP.NET MVC (que va saliendo por partes) y que en breve presentaremos un curso online sobre ASP.NET MVC de nivel medio (el otro motivo es que me cuesta muy poco ponerme delante del micro a hablar :p)

Así que sin más os dejo con los datos del webcast!

Webcast: Todavía no conoces ASP.NET MVC?

Si no has oído hablar nunca de ASP.NET MVC, o bien lo conoces de oídas pero no le has prestado atención este webcast es para tí. ASP.NET MVC es un soplo de aire fresco para el desarrollo web en tecnologías Microsoft. Tanto si eres un enamorado de ASP.NET clásico como si no lo puedes ni ver en pintura… ¿por qué no le echas una ojeada a ASP.NET MVC? ¡No te arrepentirás!

Fecha y hora: 14 de Marzo de 2012 a las 19:00 (Hora España peninsular)

Url Registro:

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032507405&Culture=es-ES

Os espero y por supuesto si conocéis a desarrolladores web que no quieran ni oír a hablar de ASP.NET, decidles que se pasen que igual se llevan una sopresita! 🙂

Explorando ASP.NET MVC4 WebAPI–3: Formatos de salida

Bueno… seguimos esta serie explorando ASP.NET WebAPI. En este post vamos a hablar de los formatos de salida. Como ya hemos dicho, de serie ASP.NET WebAPI tiene soporte para XML y para JSON. Pero… como decide el framework si enviar la salida en XML o en JSON?

La cabecera accept

Una de las cabeceras que define HTTP es la cabecera accept. Esta cabecera se usa para que el cliente informe al servidor de los tipos de datos (content type) que acepta. De nuevo un par de pruebas con fiddler nos permiten verlo fácilmente. Este va a ser nuestro controlador:

  1. public class ValuesController : ApiController
  2. {
  3.     public IEnumerable<int> GetAll()
  4.     {
  5.         return Enumerable.Range(1, 30);
  6.     }
  7. }

Y ahora de nuevo usamos fiddler para crear y ver una petición GET a /api/values, como la siguiente:

GET http://worldoffighters.epnuke2.com:55603/api/values HTTP/1.1
User-Agent: Fiddler
Host: worldoffighters.epnuke2.com:55603

La respuesta recibida es:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 19 Feb 2012 20:08:20 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Connection: Close
Content-Length: 82

[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]

Bueno, parece pues claro que ante cualquier ausencia de accept, la salida se envía en JSON (content-type: application/json). Añadimos ahora una cabecera accept:

image

Y generar una petición como la que sigue:

GET http://worldoffighters.epnuke2.com:55603/api/values HTTP/1.1
User-Agent: Fiddler
Host: worldoffighters.epnuke2.com:55603
accept: text/xml

Y esta es la respuesta que recibimos ahora:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 19 Feb 2012 20:11:55 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: text/xml; charset=utf-8
Connection: Close
Content-Length: 543

<?xml version="1.0" encoding="utf-8"?><ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><int>1</int><int>2</int><int>3</int><int>4</int><int>5</int><int>6</int><int>7</int><int>8</int><int>9</int><int>10</int><int>11</int><int>12</int><int>13</int><int>14</int><int>15</int><int>16</int><int>17</int><int>18</int><int>19</int><int>20</int><int>21</int><int>22</int><int>23</int><int>24</int><int>25</int><int>26</int><int>27</int><int>28</int><int>29</int><int>30</int></ArrayOfInt>

Bueno, hemos visto el mecanismo que usa el framework para determinar el formato de salida: la cabecera accept (no es nada nuevo, es el standard de HTTP y de hecho ya hablé hace tiempo de como aplicarlo en ASP.NET MVC: http://geeks.ms/blogs/etomas/archive/2010/09/10/asp-net-mvc-formato-de-salida-seg-250-n-content-type.aspx).

Bueno, vamos a ver ahora como crear un tipo de salida nuevo y tenerlo vinculado a un content-type determinado.

Usando MediaTypeFormatter

Para añadir un formato de salida nuevo debemos crear una clase que derive de MediaTypeFormatter:

  1. public class MediaBinaryFormatter : MediaTypeFormatter
  2. {
  3.     public MediaBinaryFormatter()
  4.     {
  5.         SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
  6.     }
  7.  
  8.     protected override bool CanWriteType(Type type)
  9.     {
  10.         return true;
  11.     }
  12.  
  13.     protected override Task OnWriteToStreamAsync(Type type, object value, System.IO.Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, System.Net.TransportContext transportContext)
  14.     {
  15.         return Task.Factory.StartNew(() =>
  16.                                          {
  17.                                              var formatter = new BinaryFormatter();
  18.                                              formatter.Serialize(stream, value);
  19.                                          });
  20.     }   
  21. }

Hay tres aspectos interesantes a recalcar:

  1. En el constructor de la clase es donde vinculamos este serializador a un content-type específico, en este caso a application/octet-stream
  2. Indicamos que podemos serializar cualquier tipo .NET. Esto es porque siempre devolvemos true en el método CanWriteType. Pero podríamos devolver true solo para determinados tipos, lo que permite tener serializados personalizados para ciertos tipos de datos 😉
  3. Finalmente en el método OnWriteToStreamAsync es donde realizamos la serialización y escritura en el stream de salida. Fijaos que debemos devolver un objeto de la clase Task con el código a ejecutar, ya que ese método será llamado de forma asíncrona por el framework (aunque a nosotros no nos preocupe demasiado). En este caso el código lo que hace es usar el BinaryFormatter de .NET para enviar la serialización en bnario del objeto que reciba. Por supuesto esto es a modo de demostración, ya que es lo más anti-internet que existe: este formato de deserialización es propio de .NET por lo que tan solo un cliente .NET puede entenderlo.

Y listos! Con esto casi hemos terminado… Nos falta simplemente registrar este MediaTypeFormatter en el framework. Y siguiendo la filosofía clásica de ASP.NET MVC la configuración está en una clase estática que podemos inicializar fácilmente desde gloabal.asax. En nuestro caso basta con añadir (p.ej. en el Application_Start) la línea:

  1. GlobalConfiguration.Configuration.Formatters.Add(new MediaBinaryFormatter());

Y ahora sí que hemos terminado. Si ejecutamos una petición con fiddler poniendo application/octet-stream en la cabecera accept, esta es la respuesta:

image

Como se puede observar es una serialización binaria de .NET!

En resumen hemos visto como a través del header HTTP accept, el cliente puede especificar que formato de respuesta desea y como podemos añadir MediaTypeFormatters propios para dar soporte a otros tipos de datos que no sean JSON o XML.

Un saludo a todos!

Explorando ASP.NET MVC4 WebAPI – 2: Enrutamiento y verbos HTTP propios

Buenas! Este es el segundo post de la serie que trata sobre ASP.NET Web API una de las grandes novedades que vienen con ASP.NET MVC. El primer post de la serie fue la introducción. Lo que quiero comentar antes que nada es que esta serie la estoy escribiendo no como un tutorial de ASP.NET Web API desde el punto de vista de un experto (porque no lo soy) sino desde el punto de vista de alguien que conoce ASP.NET MVC y está empezando a explorar Web API.

Hoy vamos a tratar un poco más el tema del enrutamiento, y el uso de verbos HTTP propios.

En el post anterior vimos como simplemente llamando a los métodos como el verbo HTTP a usar, el sistema enrutaba las peticiones perfectamente:

  1. public class ValuesController : ApiController
  2. {
  3.     // GET /api/values/5
  4.     public string Get(int id)
  5.     {
  6.         return "Hola: " + id.ToString();
  7.     }
  8. }

El método Get se llama a través dela URL /api/values/xxx y el verbo HTTP GET. Si el método se llamase Post() entonces se accedería a él a través del verbo HTTP POST. Vamos a ver ahora algunas variantes, porque esto se va a poner… interesante 🙂

  1. public class ValuesController : ApiController
  2. {
  3.     public string GetAlgo(int id)
  4.     {
  5.         return "Get Algo: " + id.ToString();
  6.     }
  7.  
  8.     public string GetAlgoDistinto(int id)
  9.     {
  10.         return "Get Algo Distinto: " + id.ToString();
  11.     }
  12.  
  13. }

Bueno… La primera pregunta es… ¿Y eso funciona? Ahora nuestros métodos no se llaman Get pero empiezan por Get. Será suficiente esto? Veamos:

image

¡Muy interesante! Se nos queja diciendo que ha encontrado más de un método para invocar dada la URL /Api/Values/2 (y el método GET). Eso significa una cosa: la parte del nombre del método que sucede a Get es ignorada por el framework. Eso puede parecer una tontería, pero no lo es en absoluto, ya que me permite que los nombres de los métodos de mi controlador sean más claros:

  1. public string GetAll()
  2. {
  3.     return "Get All";
  4. }
  5.  
  6. public string GetById(int id)
  7. {
  8.     return "Get Algo Distinto: " + id.ToString();
  9. }

La URL /api/values invocará al método GetAll y la url /api/values/10 invocará al método GetById pasándole el 10.

Bueno… usando esta convención un controlador representa un recurso (p.ej. Values) y las acciones que pueden efectuarse sobre él, a través de los distintos verbos HTTP y parámetros de la URL. Esta es una visión muy REST, de hecho en REST generalmente se usa un patrón de URLs parecidos a:

  • /recursos (p.ej. /api/values)
    • GET: Obtiene la colección de recursos
    • PUT: Sustitye todos la colección de recursos por otra pasada (raro)
    • POST: Añade un recurso nuevo a la colección
    • DELETE: Elimina todos los recursos
  • /recursos/id (p.ej. /api/values/5)
    • GET: Obtiene este recurso
    • PUT: Crea el recurso con este ID, o si ya existe lo sustituye
    • POST: Añade información al elemento con este ID (modiificación)
    • DELETE: Elimina el elemento con este ID

Este patrón de URLs REST es el que nos da por defecto el routing de ASP.NET Web API

Pero, por supuesto este patrón puede no ser útil siempre, a nosotros nos puede interesar tener soporte para una URL del tipo /api/values/GreaterThan/10 que nos devuelva solo los valores superiores a 10 (por decir algo). Pues bien, eso podemos conseguirlo usando un mapeo similar al que tendríamos en ASP.NET MVC, usando el route value action. En este caso, este route value se mapea al nombre del método (al igual que los controladores clásicos) y si queremos especificar un verbo HTTP distinto de GET debemos decorar el método con el atributo específico. Además ambos métodos de routing se pueden combinar en una tabla de rutas como esta:

  1. routes.MapHttpRoute(
  2.     name: "DefaultApi",
  3.     routeTemplate: "api/{controller}/{id}",
  4.     defaults: new { id = RouteParameter.Optional }
  5. );
  6. routes.MapHttpRoute(
  7.     name: "DefaultApiRouted",
  8.     routeTemplate: "api/{controller}/{action}/{param}",
  9.     defaults: new { param = RouteParameter.Optional }
  10. );

Notad como la segunda entrada se parece mucho, pero mucho, a la entrada por defecto de ASP.NET MVC.

En este caso, las URLS (y suponiendo el verbo HTTP GET):

  • /api/values –> Invocará al método Get() o GetXXX() (sin parámetros)
  • /api/values/x –> Invocará al método Get(id) o GetXXX(id) (con un parámetro)
  • /api/values/GreaterThan/x –> Invocará al método GreaterThan(param)

Fijaos que el parámetro se llama distinto (id en la primera ruta y param en la segunda). Eso debe ser así, si usáis el mismo nombre de parámetro en ambas rutas os va a dar un error de ambigüedad en la tabla de rutas.

Verbos propios HTTP

Aunque el protocolo HTTP define un conjunto de verbos estándard (tales como GET, POST, PUT, DELETE) no hay nada que impida crearse verbos propios. En el protocolo HTTP el verbo usado no es nada más que la primera palabra que se envía en la petición. P.ej. esa es una petición GET:

GET http://www.fiddler2.com/fiddler2/updatecheck.asp?isBeta=False HTTP/1.1
User-Agent: Fiddler/2.3.9.0 (.NET 2.0.50727.5448; Microsoft Windows NT 6.1.7601 Service Pack 1; AMD64)
Pragma: no-cache
Accept-Language: es-ES
Referer:
http://fiddler2.com/client/2.3.9.0
Host: www.fiddler2.com
Connection: Close

De todos esos datos que envía el navegador si nos fijamos en la primera línea vemos que empieza por GET: eso es el verbo HTTP. Nada nos impide usar un verbo propio (otra cosa es que el servidor que está al otro lado lo entienda claro).

Quizá te preguntes por la necesidad de definir verbos nuevos HTTP. Bueno, imagina una situación como la siguiente: estás creando un juego, que expone una interfaz REST para ser consumida desde cualquier sitio. Sigue suponiendo que en dicho juego se puede atacar casillas. Una forma de hacerlo usando los verbos estándard sería una petición PUT a /Attacks/id (donde ID fuese un ID del nuevo ataque, p.ej.). Es una visión muy CRUD: atacar una casilla es crear un nuevo ataque y insertarlo. Pero otra visión podría ser una petición a /Tile/id_casilla con el verbo HTTP Attack. En esta otra visión el recurso al que accedemos es la casilla y la acción que realizamos sobre ella es atacarla. Esta puede ser una razón por la que queremos crearnos nuestros propios verbos HTTP.

Ahora la duda es si podemos gestionar peticiones que lleguen con un verbo HTTP propio usando ASP.NET Web API. La primera prueba es fácil: consiste en crear un método con un nombre determinado, p.ej. Attack y crear una petición usando este verbo HTTP. Así que creamos el siguiente método en nuestro controlador:

  1. public string Attack()
  2. {
  3.     return "Verbo attack!";
  4. }

Y luego creamos una petición a api/values usando el verbo Attack. Para usar un verbo HTTP inventado lo más rápido es usar fiddler. Abrimos fiddler, le damos a la pestaña “Composer” (en versiones anteriores era “Request Builder”) y ponemos los datos:

image

El host que veis es simplemente un alias (definido en hosts) para localhost, porque fiddler no soporta localhost.

Y el resultado que nos muestra el propio fiddler es este:

HTTP/1.1 405 Method Not Allowed
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 19 Feb 2012 09:23:13 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Connection: Close

"The requested resource does not support http method ‘ATTACK’."

Bueno… en cierto modo es lo que nos podíamos esperar… Hubiese sido demasiado bonito que funcionase así 🙂

Si queremos soportar verbos HTTP propios lo que tenemos que hacer es decorar el método apropiado con AcceptVerbs y pasar el nombre del verbo HTTP que queremos:

  1. [AcceptVerbs("Attack")]
  2. public string PerformAttack()
  3. {
  4.     return "Verbo attack!";
  5. }

Pasamos a AcceptVerbs el verbo HTTP a soportar y luego el nombre del método ya es indiferente. Si ahora repetimos la petición con fiddler, en lugar de un error 405 obtenemos un 200 (petición correcta):

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 19 Feb 2012 09:27:54 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Connection: Close
Content-Length: 15

"Verbo attack!"

Recuerda que los verbos HTTP propios no pueden ser usados por lo general desde un navegador (ni usando javascript). Así que si los usas debes ofrecer una alternativa con verbos HTTP estándard (y si quieres ser totalmente compatible con cualquier navegador limitándote a GET y POST) si tu API debe ser invocable desde un navegador. Algunas APIs REST ofrecen mecanismos built-in para esto, como el uso de X-Http-Method-Override (usado en las APIs de Google) o de X-Http-Method (usado en OData) pero ninguno de los dos está directamente soportado en ASP.NET Web API.

Bueno… espero que os haya sido interesante. En siguientes posts seguiremos explorando ASP.NET Web API que nos quedan varias cosas intersantes para ver!!

Un saludo a todos!

Explorando ASP.NET MVC4 WebApis – 1: Introducción

Bueno… ayer se animó un poco el cotarro con la salida de la beta de ASP.NET MVC4. Y ayer mismo, el Maestro realizó un post fenómenal explicando un poco todas las novedades del framework. Echadle un vistazo al post, porque es realmente espectacular (para variar :p).

De todas las novedades que aparecen en esta versión 4, yo quiero centrarme en la llamada ASP.NET Web API. A pesar de su nombre no se trata de una API nueva. En concreto se trata de un conjunto de herramientas para permitirnos a nosotros, la creación de APIs basadas en REST. Quizá os preguntaréis: Ah, ¿pero es que ahora no se podía?

Pues la verdad es que… sí. Hasta ahora si queríamos crear una API REST teníamos dos opciones. La primera era usar ASP.NET MVC y crear una aplicación cuyos controladores en lugar de devolver vistas con contenido HTML devolvieran datos en JSON o XML. La verdad es que ASP.NET MVC con su sistema de rutas y el fácil soporte para los distintos verbos http es una herramienta ideal para crear servicios REST. Y ¿la otra opción? La otra opción se llama WCF. La verdad es que al principio WCF no estaba muy bien preparada para la creación de servicios REST (nació mucho más orientada a servicios tipo RPC como servicios Web SOAP), pero con el tiempo se le fueron poniendo añadidos que culminaron con la salida de WCF Web API (http://wcf.codeplex.com/wikipage?title=WCF%20HTTP) que simplificaba al máximo la creación de servicios REST usando WCF.

Así que, ¿si ya tenemos dos opciones para la creación de servicios REST para qué añadir otra? Pues muy sencillo: para integrar a las dos anteriores. ASP.NET Web Api, recoge lo mejor de WCF Web Api y lo integra dentro de ASP.NET MVC y de esta manera obtenemos un sistema muy sencillo y potente para la creación de servicios REST. Un sistema que de fábrica nos ofrece:

  1. Negociación de contenido automática: Que permite que el servicio devuelva los datos en el formato que prefiera el cliente (p. ej. XML o JSON), sin que nosotros nos hayamos de preocupar al respecto.
  2. Soporte para consultas realizadas usando ODATA
  3. Hosting autocontenido, es decir, podemos hospedar nuestra API REST usando IIS (sin ningún problema) pero también dentro de un ejecutable propio!

Además obtenemos todos los beneficios de ASP.NET MVC: Model binding, rutas, action filters,… Y es que estamos desarrollando una aplicación ASP.NET MVC!

Creación del proyecto

Para crear un proyecto de Web API es muy sencillo, con la Beta de ASP.NET MVC 4 instalada, os aparecerá un template de proyecto nuevo llamado “ASP.NET Web API”, que os creará el esqueleto del proyecto base:

image

Como podéis ver en la figura no se diferencia en nada de un proyecto ASP.NET MVC normal… Veamos el código que nos ha generado VS para el controlador ValuesController (lo genera automáticamente):

  1. public class ValuesController : ApiController
  2. {
  3.     // GET /api/values
  4.     public IEnumerable<string> Get()
  5.     {
  6.         return new string[] { «value1», «value2» };
  7.     }
  8.  
  9.     // GET /api/values/5
  10.     public string Get(int id)
  11.     {
  12.         return «value»;
  13.     }
  14.  
  15.     // POST /api/values
  16.     public void Post(string value)
  17.     {
  18.     }
  19.  
  20.     // PUT /api/values/5
  21.     public void Put(int id, string value)
  22.     {
  23.     }
  24.  
  25.     // DELETE /api/values/5
  26.     public void Delete(int id)
  27.     {
  28.     }
  29. }

Vale, hay tres puntos a destacar:

  1. El controlador no deriva de Controller, deriva de ApiController
  2. Las acciones no devuelven ActionResult, en su lugar devuelven datos tal cual. Fijaos que en ningún sitio indicamos si estos datos serán enviados en JSON, XML u otro formato. El cliente recibirá los datos automáticamente en el formato que haya pedido.
  3. El nombre de los métodos es el nombre del verbo HTTP que se usa para acceder a ellos. Es decir en lugar de decorar un método con [HttpPost] para indicar que debe accederse a él usando POST, llamamos a este método Post.

Si miramos la tabla de rutas veremos que el código generado por VS es el siguiente:

  1. routes.MapHttpRoute(
  2.     name: «DefaultApi»,
  3.     routeTemplate: «api/{controller}/{id}»,
  4.     defaults: new { id = RouteParameter.Optional}
  5. );
  6.  
  7. routes.MapRoute(
  8.     name: «Default»,
  9.     url: «{controller}/{action}/{id}»,
  10.     defaults: new { controller = «Home», action = «Index», id = UrlParameter.Optional }
  11. );

Vemos dos entradas, la primera es la que corresponde a nuestra API REST (mapeará todas las URLS tipo /api/{controlador}). La segunda entrada es una entrada estándard de ASP.NET MVC porque podemos mezclar una API REST con controladores estándard que devuelvan vistas (o lo que sea).

Si quieremos soportar llamadas del tipo /api/{controlador}/id/texto entonces debemos modificar la tabla de rutas:

  1. routes.MapHttpRoute(
  2.     name: «DefaultApi»,
  3.     routeTemplate: «api/{controller}/{id}/{value}»,
  4.     defaults: new { id = RouteParameter.Optional, value = RouteParameter.Optional }
  5. );

Y ahora podemos añadir un método tal como el siguiente a nuestro controlador (ValuesController):

  1. public string Get(int id, string value)
  2. {
  3.     return value + » -> « + id;
  4. }

Y si llamamos a la url http://localhost:55603/api/values/3/hola obtenemos:

image

Fijaos como nos ha llamado a nuestro método y nos ha devuelto los datos en formato XML, de forma automática.

Los que hayáis desarrollado en ASP.NET MVC os dais cuenta de una cosa? Eso funciona! Fijaos que tenemos en nuestro controlador:

  1. // GET /api/values
  2. public IEnumerable<string> Get()
  3. {
  4.     return new string[] { «value1», «value2» };
  5. }
  6.  
  7. // GET /api/values/5
  8. public string Get(int id)
  9. {
  10.     return «Hola: « + id.ToString();
  11. }
  12.  
  13. public string Get(int id, string value)
  14. {
  15.     return value + » -> « + id;
  16. }

¿Os acordáis lo que pasaba cuando en un controlador clásico teníamos algo como lo siguiente?

  1. public ActionResult Index()
  2. {
  3.     return View();
  4. }
  5.  
  6. public ActionResult Index(int id)
  7. {
  8.     return View();
  9. }

¡Exacto! Pasaba (y sigue pasando en los controladores “normales”) esto:

image

En cambio en los controladores para APIs no ocurre esto: tenemos tres métodos (Get, Get(int) y Get(int, string)) y el sistema llamará correctamente a uno u otro en función de si en la URL le pasamos 0,1 ó 2 parámetros!

Bueno… Lo dejamos aquí en este post. En los siguientes iremos investigando más sobre todas las características de Web API: Iremos viendo como usar ODATA, distintos formatos de salida, autenticación y no sé… lo que se me vaya ocurriendo, sinceramente!

Un abrazo!