WinRT. Primeros pasos con ASP.NET WebAPI.

Introducción

Entre la lista de novedades añadidas a ASP.NET MVC 4 una de las más destacadas es la llamada ASP.NET Web API. Básicamente es una nueva forma muy sencilla de crear APIs basadas en REST. Muchos estaréis pensando que no estoy hablando de nada fuera de lo común. Ya que ya podíamos conseguir lo mismo anteriormente. Y tenéis toda la razón. Ya teníamos la posibilidad de usar WCF o ASP.NET MVC cuyos controladores devolviesen datos directamente (XML o Json). La potencia no radica en nueva funcionalidad o una reinvención de la rueda. ASP.NET Web API lo que aporta es la rapidez y la simplicidad para conseguir lo mismo. Entre las opciones más destacables debemos resaltar:

  • Negociación de contenidos. El servidor puede devolver los datos en el formato que el cliente prefiera. Por defecto, viene con soporte para XML o Json entre otros.
  • Posibilidad de realizar consultas directas usando OData.
  • Podemos hospedar nueva Api en IIS.
  • Capacidades de MVC como los mecanismos para la validación, bindings, pruebas unitarias, etc.

En la entrada de hoy vamos a crear dos proyectos. Un proyecto inicial ASP.NET MVC donde crearemos un Web API muy simple que devolverá un Json. Y posteriormente una aplicación Windows Store que consumirá la información ofecida por la api.

Interesante, ¿verdad?. Manos a la obra.

Creando el WebAPI

Comenzamos creando el proyecto Web API. Es muy sencillo. Abrimos Visual Studio 2012 RC y creamos un nuevo proyecto. Seleccionamos las plantillas Web y dentro de las plantillas “Aplicación web de ASP.NET MVC 4”:

Se nos abrirá una ventana como la siguiente donde elegiremos el proyecto de tipo “Web API“:

Tras aceptar se nos habrá creado la estructura básica del proyecto:

Nos centramos primero en la carpeta Models (vacía por defecto). Debemos decidir que tipo de información es la que vamos a tratar. Este ejemplo será lo más simple posible. Vamos a crear un Modelo para tratar con películas. El modelo no es más que un objeto que representa los datos que vamos a tratar en nuestra aplicación. Vamos a añadir una nueva clase llamada Film.cs:

public class Film
{
     public int FilmID { get; set; }
     public string Title { get; set; }
     public int Year { get; set; }
}

Para añadirla hemos realizado clic derecho sobre la carpeta “Models” y hemos elegido la opción “Añadir Clase”. Como podéis observar hemos creado una clase de lo más simple posible. Sencillamente tenemos el id de la película, su título y el año de estreno.

Continuamos. Vamos a añadir el controlador. El controlador será el encargado de administrar y tratar las peticiones HTTP realizadas. Para ello hacemos clic derecho sobre la carpeta “Controllers” y seleccionamos la opción “Añadir Controlador”. Se nos abrirá una ventana como la siguiente:

Indicamos el nombre del controlador (en nuestro ejemplo FilmController) y aceptamos. Añadimos el código del controlador:

public class FilmController : ApiController
{
     Film[] films = new Film[]
     {
          new Film{ FilmID=1, Title="Gladiator",Year=2000},
          new Film{ FilmID=2, Title="Una mente maravillosa",Year=2001},
          new Film{ FilmID=3, Title="El padrino",Year=1972},
          new Film{ FilmID=4, Title="La lista de Schindler",Year=1993},
          new Film{ FilmID=5, Title="El rey león",Year=1994},
          new Film{ FilmID=6, Title="Forrest Gump",Year=1994},
          new Film{ FilmID=7, Title="Piratas del Carible",Year=2006}
     };

     public IEnumerable<Film> GetFilms()
     {
          return films;
     }

     public Film GetFilmById(int id)
     {
         var film = films.FirstOrDefault((p) => p.FilmID == id);
         if (film == null)
              throw new HttpResponseException(HttpStatusCode.NotFound);

         return film;
    }

    public IEnumerable<Film> GetFilmsByYear(int year)
    {
         return films.Where(f => f.Year == year);
    }
}

Antes de explicar la función que llevará a cabo el controlador (muy simple) vamos a analizar una serie de puntos importantes:

  • Si os fijáis el controlador es “especial”. No hereda como venía siendo habitual de Controller, sino de la clase ApiController.
  • El controlador devolverá datos (no un ActionResult como venía siendo habitual). No debemos indicar que tipo de datos serán enviados. El cliente recibirá los datos en el formato pedido.
  • Los nombres de los métodos se nombran en función de la acción HTTP realizada. Métodos con nombre Get[Nombre]() para peticiones HTTP de tipo GET y métodos con el nombre Post[Nombre]() para peticiones HTTP de tipo POST.

En nuestro ejemplo, para mantener la sencillez buscada desde el inicio en el ejemplo, hemos creado un array de películas. Dentro del controlador definimos tres métodos:

  • GetFilms. Devuelve toda la colección de películas.
  • GetFilmsById. Obtiene una película en concreto dado su ID.
  • GetFilmsByYear. Obtiene el listado de películas correspondientes a un año de estreno en concreto.

¿Cómo se pide la información por parte del cliente?

Fácil. Para entenderlo todo correctamente vamos a pararnos a analizar la tabla de rutas (archivo global.asax):

 routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Gracias a esa entrada se pueden realizar peticiones GET del tipo:

/api/film/

La tabla de rutas dirigirá hacia la acción Get() (en nuestro caso GetFilms()) del controlador FilmController devolviendo la colección creada.

De este modo podemos acceder a cada método mediante una URI:

  • GetFilms. La URI sería /api/film.
  • GetFilmsByID. La URI sería /api/film/id donde id es el id de la película deseada.
  • GetFilmsByYear. La URI sería /api/film/?year=año donde año sería el año de estreno de las películas deseadas (por ejemplo api/film/?year=2005).

Está bien, vayamos al grano. Compilemos (F5). Si todo ha ido correctamente debemos ver en el navegador una pantalla como la siguiente:

Si has visto la pantalla anterior, enhorabuena!. Todo va perfectamente.

Si quieres obtener la información de la api escribe en el navegador una URL como la siguiente:

http://localhost:1234/api/film

El resultado obtenido será un fichero Json.

NOTA: En la URL, tras localhost que apunta a tu propia máquina, el puerto indicado en el ejemplo (1234) es inventado y no siempre será el mismo. No te preocupes.

Puedes descargar el pequeño Web API creado:

Creando la aplicación Windows 8 (XAML /C#)

Segunda parte (esta si es buena). Una vez creado el proyecto Web API vamos a crear una aplicación Windows Store para consumir el Web API.

Como siempre solemos hacer vamos a realizar un ejemplo lo más simple posible pero que nos sea válida para lograr nuestros objetivos. La plantilla selecciona para realizar el ejemplo lo más simple posible será “Blank Application”.

Comenzamos. Necesitamos obtener la información de cada película. Para gestionar la misma nada mejor que crearnos un objeto donde almacenar la información. Creamos una carpeta “Models” y añadimos una nueva clase:

public class Film
{
     public double FilmID { get; set; }
     public string Title { get; set; }
     public string Year { get; set; }
}

Tras crear la clase Film ya podemos gestionar la información de cada película. Ahora debemos obtenerla. Para ello vamos a crear un ViewModel que se encargará de abastecer a la interfaz de usuario con la colección de películas obtenidas del Web API. Creamos una carpeta “ViewModels” y añadimos una nueva clase:

public class MainPageViewModel
{

}

Definimos las variables a utilizar en el ViewModel. Por un lado utilizaremos un objeto de tipo HttpClient utilizado para conectar con el Web API y obtener la información. Por otro lado, utilizaremos un ObservableCollection para vincular con la interfaz de usuario:

#region Privates

private HttpClient _httpClient;
private ObservableCollection<Film> _films;

#endregion

NOTA: El HttpClient se define en un espacio de nombres System.Net.Http.

En el constructor inicializamos el WebClient.

public MainPageViewModel()
{
     //Init
     _films = new ObservableCollection<Film>();
     _httpClient = new HttpClient();
     _httpClient.BaseAddress = new Uri("http://localhost:3479/");
     _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

Definimos una propiedad pública que abastecerá a la vista:

#region Properties

public ObservableCollection<Film> Films
{
     get { return _films; }
}

#endregion

Por último, creamos un método que será el encargado de conectar con el Web API, parseará el Json y nos rellenará la colección creada (films) con las películas obtenidas:

#region Methods

private async void GetFilms()
{
     var response = await _httpClient.GetAsync("api/film");

     if (response.IsSuccessStatusCode)
     {
          var films = await response.Content.ReadAsStringAsync();
          var film = JsonArray.Parse(films);

          var query = from f in film
          select new Film
          {
               FilmID = f.GetObject()["FilmID"].GetNumber(),
               Title = f.GetObject()["Title"].GetString(),
               Year = f.GetObject()["Year"].GetNumber().ToString()
          };

          foreach (var f in query)
          {
               _films.Add(f);
          }
     }
}

#endregion

En WinRT no tenemos implementado DataContractSerializer para JSON. En lugar de utilizar el método ReadAsync<JsonArray>, utilizaremos el método ReadAsStringAsync<string>.

Añadimos en el contructor del ViewModel la llamada al método que obtendrá las películas:

//Load
GetFilms();

Llega el turno de definir la interfaz. Nos centramos en el archivo MainPage.xaml. Definimos un control GridView que se abastecerá de la colección de películas definidas en el ViewModel:

<GridView ItemsSource="{Binding Films}" Margin="50,150,0,0">
     <GridView.ItemTemplate>
          <DataTemplate>
               <StackPanel Width="250" Height="150" Margin="10" Background="Red">
                    <TextBlock Text="{Binding Title}" TextWrapping="Wrap" FontSize="32" HorizontalAlignment="Center" Margin="10"/>
                    <TextBlock Text="{Binding Year}" FontSize="18" HorizontalAlignment="Right" Margin="10"/>
               </StackPanel>
          </DataTemplate>
     </GridView.ItemTemplate>
</GridView>

Para que todo funcione correctamente debemos indicar el ViewModel creado como DataContext de la vista:

public MainPage()
{
     this.InitializeComponent();

     DataContext = new MainPageViewModel();
}

Todo listo. Tras ejecutar la aplicación obtendremos el siguiente resultado:

Todas las películas obtenidas del Web API mostrando tanto el título como el año de estreno (tal cual definimos en el DataTemplate del GridView).

Puedes descargar el ejemplo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Cualquier duda o sugerencia podéis plantearlas en los comentarios.

Más información

5 pensamientos en “WinRT. Primeros pasos con ASP.NET WebAPI.

  1. Muy buena info !!!

    Quería preguntarte una cosa, sabes alguna manera de autentificarse en una web api.
    Mi idea es desde una llamada cliente con jquery, pero necesito que haya alguna validación con el usuario que pide los datos.

    Tienes idea de como hacerlo.

    Muchas gracias.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s