Herramienta: HFS – Http File Server

Muy buenas! Cuando preparo demos de HTML5 y JS, si no hay involucrado un servidor de por medio, no suelo utilizar VS para generar el proyecto si no algún editor más liviano, como Sublime Text o Notepad++ (personalmente prefiero el primero mil veces al segundo).

El único problema reside en que algunos navegadores, por seguridad, no ejecutan Javascript cuando el origen es file:// (es decir cuando estamos cargando un fichero del sistema de ficheros). P. ej. tengo una página que usa el API de geolocalización de HTML5 para mostrar mis coordenadas y cuando la cargo desde el sistema de ficheros, Chrome deniega la petición para geolocalización automáticamente, sin preguntar:

image 

Por otro lado IE no es tan restrictivo, pero me salta con un mensaje diciendo que los scripts (o ActiveX) se han bloqueado y un botón para permitir su ejecución:

image

Bien, aunque esto personalmente me gusta (es una buena medida de seguridad) a veces, cuando preparas demos, da un poco por el saco. La solución es, obviamente, servir los ficheros via http, desde un servidor web, así que busqué la manera más sencilla de hacerlo.

Una es, teniendo instalado IIS, copiar los ficheros al directorio Inetpubwwwroot de IIS, pero hacer esto cada vez (además con un directorio protegido con derechos de administrador) es un peñazo.

Otra es crear un proyecto ASP.NET en Visual Studio, meter allí los html y ejecutarlo. Pero claro, iniciar VS tan solo para ejecutar un par de htmls y javascripts me parece excesivo. Pero vaya, eso es más o menos lo que iba haciendo, hasta que un día me dije “tiene que haber una manera más sencilla”.

Y nada, así di con HFS (Http File Server): un pequeño programa que al ejecutarlo crea un servidor http y empieza a servir los ficheros que tu le digas. Una vez lo descargas y ejecutas (no se instala ni nada), aparece la ventana principal:

image

Y luego tan solo arrastras los ficheros que quieres servir via http. P. ej. si arrastro el fichero c:personalgeolocalizacion.html automáticamente aparece en la lista de la izquierda, indicando que ya se puede acceder a él, via http:

image

Lo bueno: El fichero NO se copia en ningún otro directorio, ni nada parecido. No hay nada más a configurar. Ahora ya puedo abrir un navegador y ver mi fichero servido via http:

image 

Fíjate como ahora, la página está servida via http y Chrome si que me pregunta si quiero compartir mi ubicación con localhost:8080 (tal y como manda la especificación de HTML5).

Personalmente me parece una herramienta muy sencilla y útil y la quería compartir con todos vosotros 🙂

Un saludo a todos!

[WaveEngine] Primeros pasos…

Buenas! Hace algunos días, no muchos, que me estoy pegando (en el buen sentido de la palabra) con WaveEngine, esta maravilla que han creado los chicos de Plain Concepts.

Disclaimer: Este post (y todos los que puedan venir) no pretenden sustituir la documentación oficial. No me considero un experto en Wave ni de lejos, realmente soy un aprendiz de nivel 1 🙂 Simplemente voy a expresar mis experiencias y lo iré haciendo a medida que las vaya teniendo, así que bueno… puede haber inexactitudes, errores, omisiones, etc… en estos posts. Así que comentarios son más que bienvenidos.

Introducción – ¿Qué es Wave Engine?

Bueno, pues básicamente WaveEngine es un motor multiplataforma de videojuegos. No es el único hay una larga lista de ellos (algunos más multiplataforma que otros) como cocos2d (y sus derivados tales como cocos2dx), Delta Engine o el todopoderoso Unity3D. Todos ellos nacen con filosofías distintas, lo que termina redundando en características, y precios, distintos.

Wave Engine es totalmente gratuito: la descarga es gratuita y no hay que pagar licencia de ningún tipo ni royalty por juego publicado ni nada parecido. El único detalle a tener en cuenta es que Wave Engine permite desarrollar para iOS y Anrdoid a través de Monotouch y Monodroid (de Xamarin) y esos productos no son libres. Aquí pues hay un coste, que es la licencia de Monotouch y Monodroid. Por supuesto esto os aplica tan solo si quereis desplegar en Android o iOS.

Como todo motor de videojuegos, Wave nos ofrece una API de relativo alto nivel para evitar tener que lidiar directamente con DirectX (o OpenGL), además de integrar muchas otras facetas: animaciones, motores de física, etc. En definitiva, un ahorro de tiempo considerable.

Panorama actual del desarrollo de videojuegos en Windows 8

En Windows 7 y anteriores la situación del desarrollo de videojuegos era relativamente sencilla. Básicamente, motores de terceros aparte, había dos opciones básicas:

  1. Usar C++ y DirectX directamente. La opción más potente y la menos productiva ya que DirectX es una API de bajo nivel.
  2. Usar .NET (C#) y XNA. Una opción que ha sido muy usada por desarrolladores indie y pequeños estudios ya que XNA es una API de medio nivel, que evita que uno tenga que pegarse con DirectX directamente.

Con Windows 8 y la aparición de las nuevas aplicaciones para la Windows Store, el panorama ha cambiado. XNA no permite realizar aplicaciones para la Windows Store y además MS lo ha discontinuado. No habrá una futura versión de XNA.

El panorama oficial para desarrollar videojuegos para la Windows Store ahora es:

  1. Usar XAML y C#. No es óptimo ni de lejos, ya que no se usa toda la potencia gráfica del ordenador.
  2. Usar C++ y DirectX… Lo que después de venir usando XNA es un paso atrás en productividad descomunal.

Por suerte, la comunidad no se está quieta, y así ha surgido el proyecto SharpDX. SharpDX es un wrapper en .NET para DirectX. Usándolo podemos desarrollar videojuegos en C# y DirectX. Aunque es una mejora no te creas que es la panacea: DirectX es de bajo nivel por lo que SharpDX también lo es. Otra alternativa interesante es MonoGame que es un port de XNA. Como su nombre indica usa Mono (Monotouch y Monodroid) para permitir desarrollar videojuegos para iOS y Android y usa por debajo SharpDX para permitir hacer lo mismo para aplicaciones Windows Store.

Y finalmente un escalón por encima están los motores de videojuegos, como Wave. Por supuesto Wave por debajo usa SharpDX pero nosotros quedamos completamente al margen.

Estructura de un proyecto de Wave

Cuando instalamos Wave Engine nos aparecen nuevas plantillas de proyecto en VS2012:

image

Si seleccionamos la opción de “Game Project” VS2012 nos añadirá dos proyectos a nuestra solución. Uno con el nombre que hayamos elegido y otro con el añadido “Project” al final. No sé todavía porque se crean esos dos proyectos pero realmente el primero es el ejecutable y es una lanzadora del segundo. Supongo que esto es porque el primero es específico por cada plataforma mientras que el segundo (que tiene realmente todo el código) es el mismo por todas las plataformas. Sospecho que los tiros van por ahí.

A partir de ahí Wave usa conceptos muy simples de entender:

  1. Escena: Es toda la información de nuestro juego en un momento dado. P. ej. un videojuego que tuviese varios niveles  podría tener varias escenas. Otra opción sería tener una escena para el menú principal y otra para el juego en sí. En un momento dado se está ejecutando (por decirlo de algún modo) una escena.
  2. Componente: Es la unidad de modularización de Wave. Los componentes son como “piezas” que se añaden a las entidades. P.ej. para posicionar algo en pantalla (si estamos haciendo un juego 2D) vamos a necesitar un componente llamado Transform2D. Todas las entidades que tengan una posición 2D tendrán una instancia de este componente.
  3. Entidad: Cada uno de los elementos de los que se compone tu juego. El héroe, la princesa o los nubarrones del fondo son entidades.
  4. Comportamientos (Behaviors): Son componentes que permiten que una entidad tenga lógica, es decir se comporte de una manera u otra. Que hace que la princesa sea una princesa indefensa y el dragón un dragón que escupa fuego? Pues sus comportamientos.

Por defecto la plantilla de proyecto de Wave nos crea la clase que representa el juego y una escena vacía. Nuestra misión es crear entidades (con sus componentes y comportamientos) y añadirlas a la escena. Y con esto tendremos un juego 🙂

Hello World con Wave Engine

Venga, empecemos por lo básico de lo básico. Vamos a crear un pequeño programa en 2D que simplemente muestre un sprite. Luego más adelante veremos como animarlo y darle un poco de vida 😉

Lo primero que debemos hacer es crear un nuevo proyecto de tipo WaveEngine Game Project. En mi caso he llamado “Mai” al proyecto.

Con esto VS2012 me va a crear los proyectos “Mai” y “MaiProject”. Como he dicho antes el segundo es el que contendrá “toda la chicha” 🙂

En MaiProject se me habrán creado los ficheros Game.cs que contiene la clase que pone en marcha el juego y MyScene.cs, la única escena que (de momento) tiene nuestro juego.

Ahora, lo único que vamos a hacer es mostrar un gráfico en pantalla. Para ello debemos introducir otro concepto de Wave: los assets.

Un asset no es nada más que un elemento que proviene de un fichero externo y que forma parte de nuestro juego. P. ej. si quiero mostrar un fichero .png este .png será un asset. Pero lo mismo ocurrirá si tengo un modelo 3D exportado en formato .x p.ej. WaveEngine no entiende de formatos gráficos o de formatos 3D o de cualquier otro formato externo. Wave entiende tan solo de un formato de asset genérico, el .wpk. Por lo tanto NO podemos usar directamente un .png, si no que debemos convertirlo antes a este formato .wpk.

Para ello debemos usar la herramienta (que se instala junto con Wave) llamada Assets Exporter. Si la ponemos en marcha veremos una interfaz muy, muy negra:

image

En mi caso tengo un fichero .png, llamado mai_idle (0).png y quiero convertirlo a un .wpk para poder usarlo desde Wave. Para ello, debo crear un proyecto nuevo de assets exporter. Así que le doy a File->New Project y selecciono una carpeta. Ello me crea un fichero .wproj y una estructura de carpetas dentro de la carpeta seleccionada. Una de esas carpetas es llamada Assets y contendrá los ficheros de origen (en mi caso el .png). Para añadir assets al proyecto basta con pulsar el botón de “+” (el primero por la izquierda) y seleccionar el fichero. Al hacerlo el fichero es copiado automáticamente a la carpeta Assets.

Una vez tenemos todos los Assets podemos darle a exportar (Project –> Export) y en la carpeta “Exports” dentro de la carpeta que hemos elegido al crear el proyecto del assets exporter tendremos el fichero .wpk.

Ahora debemos copiar este fichero a la carpeta “Content” del proyecto de VS2102 y establecer en las propiedades del fichero “Copy to output folder” a “Always”:

image

Bien! Esta es la forma habitual de proceder con los assets 🙂

A partir de ahora ya tan solo nos queda codificar. En nuestro caso vamos a mostrar tan solo una imagen. Para ello vamos a crear una entidad (todo son entidades en Wave) que va a tener varios componentes. Vamos a construirlo paso  a paso. Todo el código va en el método CreateScene de MyScene. Empezamos por crear la entidad:

var mai = new Entity(«Mai»);

Y ahora vamos a irle añadiendo componentes. Empezaremos por una posición. Haremos que mai aparezca en la esquina inferior izquierda de la pantalla. En Wave una posición es un componente de tipo Transform2D (estamos en un videojuego 2D, los 3D son otro mundo):

mai.AddComponent(new Transform2D()

    {

        X = 50,

        Y = WaveServices.Platform.ScreenHeight 46,

        Origin = new Vector2(0.5f, 1)

    });

El siguiente paso es tener un asset gráfico. De hecho Wave, como buen motor, nos da el concepto de sprite, es decir un conjunto de gráficos:

mai.AddComponent(new Sprite(«Content/mai_idle (0).wpk»));

Al constructor de Sprite se le pasa el nombre del fichero .wpk que contiene el gráfico (técnicamente la textura). Un tema a destacar, que ya veremos en otro post, es que un fichero .wpk puede contener más de un gráfico de nuestro sprite.

Finalmente tan solo nos queda añadir el renderizador, es decir el componente que se encarga de “dibujar” en pantalla. Te puede parecer extraño que los renderizadores sean componentes, pero esto permite que una misma entidad se dibuje (se renderice) en pantalla de formas distintas. ¡Modularidad ante todo!

mai.AddComponent(new SpriteRenderer(DefaultLayers.Alpha));

Nota: No la he usado en este ejemplo, pero Wave tiene una API fluent, de forma que en lugar de ir haciendo mai.XXX cada vez, podeis encadenar las llamadas a AddComponent una tras de otra.

Finalmente debemos agregar esta entidad que hemos creado a la escena:

EntityManager.Add(mai);

¡Y listos! Hemos terminado, ya podemos darle a F5 para ver nuestra obra de arte:

image

En el siguiente post veremos como darle un poco de movimiento… que si alguien se merce ser vista en pleno movimiento es Mai Shiranui 😛 😛

[C#]–Enumeraciones y corutinas

¡Buenas!

Empezamos con una pregunta:

¿Cual es el resultado de este programa?

class Program

{

    static void Main(string[] args)

    {

        var data = Foos;

        foreach (var foo in data)

        {

            ChangeFooValue(foo);

        }

 

        var firstFoo = data.First();

        Console.WriteLine(firstFoo.Value);

        Console.ReadLine();

    }

 

    private static IEnumerable<Foo> Foos

    {

        get

        {

            for (var idx = 1; idx <= 10; idx++)

            {

                yield return new Foo(idx);

            }

        }

    }

 

    private static void ChangeFooValue(Foo foo)

    {

        foo.Value = foo.Value + 10;

    }

}

 

internal class Foo

{

    public int Value { get; set; }

    public Foo(int i)

    {

        Value = i;

    }

}

¿Ya lo has meditado?

Pues ahora la solución…

Aunque el sentido común te pueda decir que el valor que se imprimirá es 11, el valor que realmente se imprime es 1.

¿Y eso? A priori todo parece claro: Tenemos una propiedad llamada Foos que nos devuelve 10 objetos Foo (con valores del 1 al 10). Nos guardamos dichos valores en data, iteramos sobre ellos y añadimos 10 al valor de cada objeto Foo. Luego imprimimos el valor del primero de esos objetos. Todo está perfecto, salvo que el resultado es 1 y no 11 como debería ser.

La clave es en como está definida la propiedad Foo (usando yield return) lo que impacta directamente en lo que es la variable data. Por qué… ¿Qué es data? ¿Es una lista? ¿Es un array? ¿Alguien lo sabe?

Cuando usamos yield return no se crea un espacio de almacenamiento para guardar los valores que vamos devolviendo. Se van creando uno tras otro tantas veces como se necesita. Realmente data no contiene ningún objeto (la frase que he usado antes de “Nos guardamos dichos valores en data” es totalmente inexacta), es como un apuntador a “una colección virtual (de 10 elementos)”. Por eso cuando iteramos con el foreach pasamos 10 veces por el yield return y cuando luego usamos el .First() pasamos otra vez más por el yield return. Aunque antes en el foreach se han recuperado los 10 elementos de Foos, como no están guardados en ningún sitio, al hacer .First() se vuelve a recuperar el primero. Lo que crea un Foo nuevo cuyo valor es 1. De ahí el resultado final.

Si usas Resharper, que sepas que te va avisar:

image

Este aviso, simplemente te indica que se está recorriendo más de una vez el mismo IEnumerable (en este ejemplo se recorre una vez con el foreach y otra vez al usar .First()). Recorrer dos veces un IEnumerable puede tener consecuencias no esperadas o puede ser perfectamente correcto. Como Resharper no tiene manera de saberlo, te avisa, para que le eches un vistazo.

Esto es así tan solo si en algún momento NO se guardan en ningún sitio los elementos recuperados. Basta con hacer:

var data = Foos.ToList();

Ahora el resultado final es 11, ya que el método .ToList() copia los valores a una List<T> por lo que ahora data si que tiene almacenados los 10 valores Foo. Y cuando hacemos data.First() recuperamos simplemente el primer valor almacenado en data.

Un caso real…

Bien, probablemente pienses que esto tampoco tiene mucha importancia porque tu no vas por ahí haciendo “colecciones virtuales” con yield, pero que sepas que hay alguien que si que lo hace: alguien llamado EF. En un proyecto en el que estuve nos encontramos con este comportamiento precisamente con el uso de EF: Usábamos EF para recuperar ciertos registros de la BBDD que luego convertíamos a DTOs con un método extensor que dado un IEnumerable<T> devolvía un IEnumerable<TDto>. Dicho método extensor iteraba sobre el IEnumerable<T> original y devolvia otro IEnumerable de Dtos:

public static IEnumerable<R> Map<T, R>(this IEnumerable<T> source)

{

    foreach (var t in source)

    {

        yield return Mapper.Map<T, R>(t);

    }

}

(En nuestro caso la clase Mapper era AutoMapper).

A priori parece todo correcto: Obtenemos datos de EF y los mapeamos a DTOs. Si nos limitamos a devolver el IEnumerable obtenido por Map<T,R> todo va perfecto. El problema es si modificamos alguno de los DTOs que hemos obtenido. Cuando volvemos a iterar sobre la variable que contiene los resultados volvemos a obtener los resultados originales. Eso es debido a que EF crea una colección virtual (es decir usa yield return) para devolvernos los resultados y nuestro Map<T,R> hace lo mismo, por lo que en ningún momento hemos “guardado” esos datos en ningún sitio. Estamos en la misma situación que el ejemplo inicial de este post.

La solución pasa por materializar (es decir llamar a .ToList() o .ToArray()) el resultado devuelto por EF.

Para finalizar solo comentar que el uso de yield return en C# es un ejemplo de lo que se conoce como “corutina”. Una corutina no deja de ser una subrutina (es decir una función o pedazo de código) pero que es reentrante en distintos puntos. Otro ejemplo de corutinas en C# lo puedes encontrar en el uso de la palabra clave await (en C# 5).

¡Un saludo!

Combos en ASP.NET MVC

Buenas! Una de las preguntas más referentes en ASP.NET MVC consiste en como crear combos, enlazarlas, etc, etc… La verdad es que la documentación sobre este punto es un poco difusa y dispersa así que intentaré en este post mostrar un poco las distintas formas que tenemos en ASP.NET MVC de crear combos.

Para ilustrar las distintas opciones partimos de una clase “Database” que simula un contexto de ORM. Es una clase que simplemente tiene dos listas (estáticas), una de ciudades (Cities) y otra de provincias (States). La definición de las clases City y State son:

    public class City

    {

        public int Id { get; set; }

        public string Name { get; set; }

        public string CP { get; set; }

        public int StateId { get; set; }

    }

 

    public class State

    {

        public int Id { get; set; }

        public string Name { get; set; }

    }

1. SelectListItem

En HTML una combo (<select>) contiene una lista de opciones que siempre son clave y texto que se muestra (ambos alfanuméricos). Para representar esta información en ASP.NET MVC disponemos de la clase SelectListItem. SelectListItem nos permite almacenar la clave (Value) y el texto (Text), así como un valor booleano (Selected) que indica si este es el elemento seleccionado por defecto a la combo (se corresponde al atributo selected del tag <option>).

Una posible forma de usarlo sería así:

var items = new List<SelectListItem>();

items = Database.Cities.Select(c => new SelectListItem()

    {

        Text = c.Name,

        Value = c.Id.ToString()

    }).ToList();

 

ViewBag.Cities = items;

return View();

Obtenemos las ciudades y luego convertimos cada objeto “City” en un objeto SelectListItem. Finalmente guardamos esta lista de SelectListItem en el ViewBag.

Para mostrar esta combo basta con usar en la vista:

@Html.DropDownList("Cities")

El nombre usado “Cities” es el nombre del campo usado en el ViewBag y donde se encuentra la lista de SelectListItem.

La combo generada tendrá un atributo name llamado Cities y esto es importante a la hora de recibir el valor seleccionado de la combo. Hay una gran confusión en esto. Una combo envia UN SOLO ELEMENTO al controlador: El ID del elemento seleccionado.

Veamos como podemos recibir la ciudad seleccionada:

[HttpPost]

public ActionResult Index(string Cities)

{

    var id = Int32.Parse(Cities);

    // Recuperamos la ciudad ==> Consulta a BBDD

    var city = Database.Cities.FirstOrDefault(c => c.Id == id);

    // Operamos con la ciudad

}

Dos cosas a destacar:

  1. Lo que recibimos en Cities NO es la lista de ciudades. Es el valor de la propiedad Value del SelectListItem seleccionado (en mi caso el ID de la ciudad seleccionada).
  2. El nombre del parámetro (Cities) es el mismo que el nombre del campo del ViewBag (y el mismo que pusimos en la llamada a Html.DropDownList).

2. IEnumerable

Tener que convertir siempre nuestros datos (en este caso una lista de ciudades) a una lista de SelectListItem es muy pesado. Por suerte hay una clase SelectList que hace esto por nosotros. Basta con pasarle el IEnumerable que queremos, el nombre de la propiedad que es la clave y el nombre de la propiedad que contiene el texto a mostrar.

public ActionResult Index()

{

    var items = Database.Cities;

    ViewBag.Cities = new SelectList(items, "Id", "Name");

    return View();

}

En este punto ViewBag.Cities contiene una SelectList (que implemente IEnumerable<SelectListItem>) y el resto del código ya es exactamente el mismo que antes.

3. Otros orígenes de datos

Hasta ahora en la vista hemos usado Html.DropDownList pasándole tan solo una cadena (Cities). Esta cadena determina:

  • El nombre del atributo name del <select> generado. Que a su vez es el nombre del parámetro cuando recibimos los datos
  • El nombre del campo del ViewBag que tiene los elementos.

Si no queremos que estos dos valores sean iguales, podemos espcificarle a Html.DropDown donde está el IEnumerable<SelectListItem> que contiene los datos de la combo. Así en la vista podríamos utilizar:

@Html.DropDownList("selectedCity", ViewBag.Cities as IEnumerable<SelectListItem>)

Con esto le estamos diciendo que nos genere un <select> cuyo atributo name valga “selectedCity” y que los datos están en ViewBag.Cities.

Ahora cuando recibimos los datos debemos tener presente que el parámetro ya NO se llama Cities, si no selectedCity:

[HttpPost]

public ActionResult Index(string selectedCity)

{

    var id = Int32.Parse(selectedCity);

    // Recuperamos la ciudad ==> Consulta a BBDD

    var city = Database.Cities.FirstOrDefault(c => c.Id == id);

    // Operamos con la ciudad

}

4. HtmlDropDownListFor

Este helper lía un poco porque tendemos a compararlo con el resto de helpers similares. Así, si yo hago Html.TextboxFor(m=>m.Name) me va a generar un Textbox vinculado a la propiedad Name del ViewModel de la vista. HtmlDropDownListFor también espera una propiedad del modelo pero NO es la propiedad que tiene los elementos, si no donde dejará el valor del elemento seleccionado.

Mucha gente se confunde y se cree que la propiedad que pasamos a Html.DropDownListFor es la propiedad que contiene los valores a mostrar. Imaginemos que tenemos el siguiente ViewModel:

public class ComboCitiesViewModel

{

    public IEnumerable<City> Cities { get; set; }

    public int SelectedCity { get; set; }

}

La acción Index nos queda ahora de la siguiente forma:

public ActionResult Index()

{

    var items = Database.Cities;

    var vm = new ComboCitiesViewModel();

    vm.Cities = items;

    return View(vm);

}

Para usar Html.DropDownListFor podemos hacerlo tal y como sigue:

@Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))

Le paso DOS parámetros a Html.DropDownListFor:

  1. La propiedad del ViewModel que contendrá el valor seleccionado
  2. El IEnumerable<SelectListItem> con los datos. Fijaos que en este caso dado que mi ViewModel contiene un IEnumerable<City> uso la clase SelectList que hemos visto antes para hacer la conversión.

Para recibir los datos puedo declarar la siguiente acción:

[HttpPost]

public ActionResult Index(ComboCitiesViewModel info)

{

    var id = info.SelectedCity;

    // Recuperamos la ciudad ==> Consulta a BBDD

    var city = Database.Cities.FirstOrDefault(c => c.Id == id);

    // Operamos con la ciudad

}

Y aquí es donde hay otro punto de confusión: en info NO VAS A RECIBIR la lista de ciudades. Es decir la propiedad Cities va a ser null:

image

¿Y eso? Pues bueno, simple y llanamente nadie manda estos valores de vuelta para el controlador. La lista de ciudades NO está en la petición POST que hace el navegador y por lo tanto el controlador no la recibe.

De hecho, podríamos modificar el parámetro ComboCitiesViewModel para que fuese un string llamado SelectedCity y funcionaría igual.

5. Combos encadenadas

Lo que vamos a ver es una implementación de combos encadenadas pero SIN ajax. Es decir, seleccionas provincia, envías la petición y te aparecen las ciudades. En una web “actual” seguramente se haría via Ajax, pero hacerlo de la “manera antigua” nos permitirá terminar de ver como funcionan las combos.

Antes que nada modificamos el viewmodel:

public class ComboCitiesViewModel

{

    public IEnumerable<City> Cities { get; set; }

    public int SelectedCity { get; set; }

    public IEnumerable<State> States { get; set; }

    public int SelectedState { get; set; }

}

La acción Index que envía la página inicial la modificamos para que rellene States:

public ActionResult Index()

{

    var items = Database.States;

    var vm = new ComboCitiesViewModel();

    vm.States = items;

    return View(vm);

}

La vista nos quedará de la siguiente forma:

@model MvcCombos.Models.ComboCitiesViewModel

 

@using (Html.BeginForm()) {

    <label for="Cities">Ciudad:</label>

 

        @Html.DropDownListFor(m=>m.SelectedState, new SelectList(Model.States, "Id", "Name"))

 

    if (Model.SelectedState != 0)

    {

        @Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))

    }

 

    <input type="submit" value="enviar" />

}

Es importante entender lo que hacemos en la vista:

  1. Si NO hay provincia seleccionada (Model.SelectedState vale 0) entonces mostramos la primera combo para seleccionar estado.
  2. Si hay estado seleccionado entonces generamos la combo para seleccionar la ciudad.

Nota: Este código tiene algunos problemas, como p.ej. que ocurre si el usuario selecciona una provincia, envía el formulario, y cuando aparece de nuevo la vista con las dos combos modifica la provincia seleccionada? En una aplicación real deberías, al menos, deshabilitar la combo de estados cuando ya haya estado seleccionado.

Y finalmente ahora la acción que recibe los resultados debe gestionar que será llamada dos veces (una para seleccionar el estado, la segunda con estado y ciudad):

[HttpPost]

public ActionResult Index(ComboCitiesViewModel info)

{

    if (info.SelectedState != 0 && info.SelectedCity == 0)

    {

        info.States = Database.States;

        info.Cities = Database.Cities.Where(c => c.StateId == info.SelectedState);

        return View(info);

    }

 

    var id = info.SelectedCity;

    // Recuperamos la ciudad ==> Consulta a BBDD

    var city = Database.Cities.FirstOrDefault(c => c.Id == id);

    // Operamos con la ciudad

}

Fíjate en un par de cosas:

  1. Debemos volver a cargar todos las provincias dentro del viewmodel. Si no cuando la vista intente renderizar la combo de provincias dará error.
  2. En las ciudades seleccionamos tan solo aquellas que son de la provincia que el usuario ha seleccionado.

Insisto, en una vista “real” la segunda vez no mostraríamos la combo de provincias, quizá mostraríamos el nombre de la ciudad seleccionada. Veamos como podríamos hacerlo.

Por un lado podemos modificar el viewmodel:

public class ComboCitiesViewModel

{

    public IEnumerable<City> Cities { get; set; }

    public int SelectedCity { get; set; }

    public IEnumerable<State> States { get; set; }

    public int SelectedState { get; set; }

    public string SelectedStateName { get; set; }

}

Añadimos la propiedad para guardar el nombre de la provincia seleccionada. Y en la vista usamos esta propiedad o Html.DropDownList en función de si hay o no provincia seleccionada:

@model MvcCombos.Models.ComboCitiesViewModel

 

@using (Html.BeginForm()) {

    <label for="Cities">Ciudad:</label>

 

    if (Model.SelectedState == 0)

    {

        @Html.DropDownListFor(m => m.SelectedState, new SelectList(Model.States, "Id", "Name"))

    }

    else

    {

        <text>Provincia @Model.SelectedStateName </text>

        @Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))

    }

 

    <input type="submit" value="enviar" />

}

Finalmente en la acción que recibe los datos nos ahorramos de rellenar de nuevo las provincias (ya que la vista ya no las usará la segunda vez) y ponemos el nombre de la provincia seleccionada (fíjate que hemos de ir a buscarlo a la BBDD ya que solo tenemos el ID):

[HttpPost]

public ActionResult Index(ComboCitiesViewModel info)

{

    if (info.SelectedState != 0 && info.SelectedCity == 0)

    {

        info.SelectedStateName = Database.States.Single(s => s.Id == info.SelectedState).Name;

        info.Cities = Database.Cities.Where(c => c.StateId == info.SelectedState);

        return View(info);

    }

 

    var id = info.SelectedCity;

    // Recuperamos la ciudad ==> Consulta a BBDD

    var city = Database.Cities.FirstOrDefault(c => c.Id == id);

    // Operamos con la ciudad

}

Con esta aproximación:

  1. La primera vez la vista mostrará la combo de provincias y el controlador recibirá en SelectedState el id de la provincia seleccionada.
  2. La segunda vez la vista mostrará un texto con el nombre de la provincia y la combo de ciudades y el controlador recibirá en SelectedCity el ID de la ciudad seleccionada. Esta segunda vez el controlador NO recibirá SelectedState ya que no se envía. En nuestro caso no es necesario ya que lo podemos sacar de la ciudad. Si fuese necesario deberíamos usar un campo Hidden.

Bueno… creo que esto más o menos es todo. ¡Espero que este post os ayude a resolver las dudas que podáis tener con las combos en ASP.NET MVC!

¡Un saludo!

HTML5 – Que tus usuarios suban su foto a su perfil (WebRTC)

Venga, seguro que como la mitad de mortales tienes una idea de negocio que consiste en hacer una web y que te la compre Google (la otra mitad esperan que la compre Microsoft :p).

Si este es el caso, ya sabes que se trata de tener cuantos más usuarios mejor (ahí tienes el caso de Mammoth que han lanzado una campaña viral para que todos nos apuntemos allí aunque no tengamos ni idea de que va). Hoy en día cualquier web que se precie tiene un perfil donde el usuario puede subir una foto suya para que sea su avatar. Imagina la situación de que un usuario se registra a tu web y no tiene a mano ninguna foto suya para subir. ¿No estaría bien que se pudiese hacer una foto con la webcam del portátil y subirla directamente? Todo ello des de tu web, por supuesto.

Pues bien, eso es ni más ni menos lo que permite WebRTC. 😉

WebRTC significa Web Real Time Communications y es una de las futuras APIs de HTML5 que más darán que hablar. Hablo en futuro porque actualmente no son un estándard terminado: la especificación actual es todavía un Working Draft. Eso significa que su soporte en navegadores es todavía muy escaso y en la mayoría de casos experimental. El código de este post ha sido probado en Chrome 26 y funciona. No he probado en otros navegadores, pero por lo que sé IE10 no soporta todavía WebRTC y por lo que he leído FF lo soporta a partir de su versión 20. Opera también parece que lo soporta pero no sé a partir de que versión. Al final no tengais ninguna duda de que IE terminará soportando WebRTC, pero como digo: no es un estándard terminado y su definición puede cambiar.

Manos a la obra

La implementación de WebRTC se basa básicamente en una función javascript llamada getUserMedia que está en el objeto navigator. De todos modos como ya digo el soporte puede ser experimental y así p.ej. en Chrome está función está prefijada y debe usarse webkitGetUserMedia. Cosas del desarrollo para web.

Nota: Personalmente lo de los vendor prefixes me parece una aberración. No sé, si una característica se soporta, se soporta y punto. No veo porque tenemos que andar prefijando cosas porque “están a medias” y tal. Al final el problema para el desarrollador es el mismo: debes acordarte de meter todos los prefijos que toquen. En CSS aún puede tener un pase pero… ¿en javascript? ¿De veras tenemos que prefijar una función javascript? A mi me parece que algo se nos está yendo de las manos, pero bueno los prefijos están ampliamente aceptados por el W3C así que supongo que será mejor tenerlos que no tenerlos.

La función getUserMedia permite obtener un stream de datos local. Resumiendo, con getUserMedia podemos obtener la imagen de la webcam o el sonido del microfono. Básicamente le pasamos dos o tres parámetros:

  1. Los streams locales que queremos capturar (p.ej audio y/o video).
  2. La función de callback a invocar cuando la captura haya empezado
  3. La función de callback en caso de error (opcional).

Así para capturar la webcam bastaría con:

navigator.getUserMedia({video: true}, onSucessCallback, onFailCallback);

Para no andar jugando con los prefijos es preferible hacer algo como:

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

Así a medida que los navegadores vayan incorporando la función (con o sin prefijo) pues ya la tendremos disponible.

Vale… capturamos un stream de video, pero lo suyo es poderlo mostrar ¿no? En HTML5 tenemos una etiqueta que nos permite mostrar vídeos (<video />). ¿No sería genial que la pudiesemos utilizar? Pues, por suerte, podemos. Para ello nos tenemos que apoyar en otra API de HTML5: window.URL

Con los métodos de window.URL podemos crear URLs “ficticias” que apunten a “objetos” (técnicamente Blobs) que están vivos dentro del documento. La idea viene a ser la siguiente: con getUserMedia capturamos un stream de video. Para mostrar videos tenemos la etiqueta <video />. Pero la etiqueta <video /> espera la URL del vídeo. Pues con window.URL vamos a poder crear esta URL.

El código es muy simple:

<!DOCTYPE html>

<html>

<head></head>

<body>

    <video autoplay></video>

    <script>

        var onErrorCallback = function (e) {

            console.log(‘Error!’, e);

        };

        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

        navigator.getUserMedia({ video: true}, function (localMediaStream) {

            var video = document.querySelector(‘video’);

            video.src = window.URL.createObjectURL(localMediaStream);

        }, onErrorCallback);

    </script>

</body>

</html>

Bueno… Si ejecutais este código veréis algo como:

image

Por supuesto no vereis a este tipo en pantalla, seguramente el que aparezca sea más feo, pero bueno eso son cosas que pasan 😛 😛 😛 😛

La función getUserMedia pide permisos. Es decir el usuario debe confirmar que da acceso a la webcam en este caso:

image

Vale… ya estamos mostrando el vídeo de la webcam. Pero el objetivo era que el usuario pudiese subir una foto de su perfil a nuestra web, ¿recordáis?

Bueno, para ello acude en nuestra ayuda otro de los nuevos elementos de HTML5: el <canvas />. Como ya sabréis la mayoría el canvas de HTML5 es un espacio dentro del documento para dibujar gráficos en 2D o en 3D.

Pues bien, la idea es volcar el frame actual del video al canvas. Y por suerte nos basta con llamar al método drawImage del contexto 2D del canvas. Sí, tan simple como esto.

Veamos el código:

<!DOCTYPE html>

<html>

<head>

    <style>

        video {width: 300px; height: 300px;}

    </style>

 

</head>

<body>

    <video autoplay></video>

    <input type="button" value="snaphsot!" id="snap" />

    <canvas></canvas>

 

    <script>

        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

        // Definición de variables globales

        var localUserMedia = null;

        var canvas = document.querySelector(‘canvas’);

        var video = document.querySelector(‘video’);

        var ctx = canvas.getContext(‘2d’);

        // Cuando cargamos el vídeo guardamos la relación

        // de aspecto y ajustamos el tamaño del canvas

        // para que se mantenga

        video.addEventListener(‘loadedmetadata’, function (e) {

            var relation =  e.target.videoWidth/e.target.videoHeight;

            canvas.width = 300;

            canvas.height = 300/relation;

        }, false);

        // Capturamos el frame actual del video

        document.getElementById(‘snap’).addEventListener(‘click’, function (e) {

            if (localUserMedia) {

                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            }

        }, false);

        // Callback de error de getUserMedia

        var onErrorCallback = function (e) {

            console.log(‘Error!’, e);

        };

        // Capturamos el video con getUserMedia y lo

        // mandamos a un vídeo

        navigator.getUserMedia({ video: true }, function (localMediaStream) {

            var video = document.querySelector(‘video’);

            video.src = window.URL.createObjectURL(localMediaStream);

            localUserMedia = localMediaStream;

        }, onErrorCallback);

    </script>

</body>

</html>

He puesto comentarios en el código para que sea más fácil de seguir. Pero la clave está en que ahora al pulsar el botón de “snapshot” utilizamos drawImage para volcar el contenido del frame actual del vídeo al canvas.

Una vez tenemos la imagen en un canvas ya tenemos vía libre! Por un lado podríamos utilizar el propio canvas para permitir que el usuario manipule la imagen y luego subirla via Ajax (ver mi post Crea tu propio Instagram) o bien podemos directamente volcar el contenido del canvas en una imagen (utilizando toDataURL del propio canvas).

No voy a poner en este post como subir los datos del canvas al servidor porque sería repetir lo que puse en el post de Crea tu propio Instagram (Paso 5 del post).

En fin… hemos visto como gracias a WebRTC podemos (podremos) hacer algo que hasta hace poco parecía fuera totalmente de las posibilidades de la web: el acceso a dispositivos locales tales como micro y webcam. Y WebRTC no se queda ahí! Según la especificación será posible montar meetings on-line utilizando plataforma 100% web! Pero esta parte está todavía en una fase muy experimental e inicial de implementación!

Un saludo!

Objective-C para desarrolladores de C# (ii)–Punteros

Aaahhh… los punteros son una de las bestias negras del desarrollo. Desterrados de los dominios de los lenguajes orientados a objetos “modernos” como Java por ser demasiado “próclives a errores” los punteros se han convertido en una especie de ser mitológico, temido por muchos desarrolladores que tiemblan cuando ven un asterisco dando vueltas por ahí… Incluso C# los tiene medio apartados por ahí, rodeados de unsafes por todas partes.

¿Qué es un puntero?

Un puntero no es nada más que una variable normal y corriente pero que su valor en lugar de ser un entero, o un carácter, o un número decimal es una dirección de memoria:

int *a;

int i=10;

a=&i;

La primera línea declara un puntero a int. No hay un tipo de datos específico para puntero, en su lugar se pone un asterisco que sigue al tipo de datos.

Nota: El tipo de datos de la variable a (el puntero) es int*. Que en mi código haya un espacio entre el int y el * y ninguno entre el * y la a es porque el parser es así de majo y me deja hacerlo. Verás otra gente que teclea int* a; y es equivalente (y estrictamente hablando más cierto).

La segunda línea es obvia (declara un int) y la tercera línea utiliza el operador de referencia (&) para obtener la dirección de la variable i y asignarla al puntero a.

En este punto el valor de a es la dirección de memoria de la variable i. Si tengo un puntero puedo modificar el contenido de dicho puntero utilizando el operador de dereferencia (*):

*a=11;

En este punto el contenido del puntero a vale 11. O dicho de otra manera: el valor de posición de memoria a la que apuntaba el puntero ha pasado a valer 11. ¿Y qué había en esta posición de memoria? Pues la variable i. Así si ahora imprimo la variable i veré que vale 11.

O de forma más clara, *a es equivalente a i. Modificar el valor de *a implica modificar el valor de i (y a la inversa, modificar el valor de i implica modificar el valor de *a).

¿Por qué son peligrosos los punteros?

Per se, los punteros no son peligrosos. Son simplemente un alias para acceder a una posición de memoria. Pues entonces, ¿qué es lo que los hace peligrosos?

Pues su peligro reside en lo que se llama aritmética de punteros y que permite modificar no el contenido de un puntero si no el propio puntero en sí. Eso significa que un puntero tiene la capacidad de apuntar a direcciones arbitrarias de memoria:

int *a;

int i=10;

a=&i;

a = a + 0x300;

*a=11;

Fíjate en la penúltima línea: Le estamos sumando 0x300 (768) a la dirección de a. De forma que ahora a apunta 768 elementos más allá de la dirección de memoria de i. Cuando modifico el contenido de a, estoy modificando una dirección de memoria arbitraria y lo más normal es que:

image

El otro problema típico de los punteros, no es tanto de los punteros en sí, si no del runtime del lenguaje (me da igual si es C/C++ o Objective-C). En runtimes dotados de garbage collector (como el CLR), el propio sistema se encarga de destruir aquellos objetos que no se usan. ¿Y como sabe el runtime que nadie usa un objeto? Pues, porque no hay referencias que apunten a él. El hecho de tener un GC nos garantiza de que las referencias siempre apuntan a un objeto válido (ya que el GC no destruirá un objeto mientras tenga referencias que lo apunten). Pero, que ocurre si no tenemos GC? Pues que puedo tener dos referencias que apunten a un objeto y alguien puede destruir este objeto. Cuando luego más tarde uso una de esas referencias para acceder al objeto, me puede dar un error ya que en la dirección de memoria apuntada por esta referencia ya no está el objeto, hay otros datos. Este error viene a ser el contrario del NullReferenceException: En lugar de tener un error porque la referencia NO apunta a nada (vale null), tengo un error porque la dirección de memoria a la que apunta la referencia ya no contiene el objeto que contenía porque este ha sido destruído.

He estado usando en todo este párrafo la palabra referencia y no puntero, para poner de manifiesto que podríamos tener este error también si usáramos un lenguaje basado en referencias (y no en punteros) como C# si tuviesemos una gestión manual de memoria. La principal causa de errores de C/C++ es la gestión manual de memoria, no los punteros en sí. En los lenguajes que tienen gestión manual de memoria se denomina con el término dangling pointer a un puntero que apunta a una dirección de memoria donde ya NO hay el objeto que había.

No voy a entrar en las diferencias entre punteros y referencias (porque son muy tenues y depende un poco de cada lenguaje). Quédate con que tanto un puntero como una referencia apuntan a una dirección de memoria. Si tienes GC puedes estar seguro de que en esta dirección habrá un objeto válido. Si no tienes GC entonces NO puedes estar seguro de esto y ahí empiezan realmente tus problemas. La única característica que tienen los punteros y no tienen las referencias es la aritmética de punteros.

¿Cual es la posición de Objective-C?

Primero, Objective-C es un superconjunto de C (eso significa que todo el código C es código Objective-C válido). C tiene punteros y aritmética de punteros así que Objective-C también.

Lo que diferencia Objective-C de C es la gestión de memoria. En C (y en C++) la gestión es totalmente manual: Cuando quieres crear un objeto debes reservar la memoria una sola vez y luego liberarla una sola vez cuando ya nadie más vaya a usar el objeto.

Òbjective-C usa un contador de referencias para ello: El runtime mantiene un contador que indica cuantos punteros apuntan a un objeto en un momento dado. Cuando dicho contador llega a 0 el runtime destruye el objeto. Hay dos modelos de gestión de memoria dentro del runtime:

  1. Manual: Nosotros somos los encargados de indicarle al runtime cuando queremos que incremente y decremente dicho contador. Este modelo de memoria adolece de los mismos problemas que tiene C/C++ para gestionar la memoria (memory leaks si no decrementamos suficientes veces el contador o dangling pointers si lo decrementamos demasiadas veces).
  2. Automática (ARC): El encargado de decrementar o incrementar el contador es el compilador. La verdad es que ARC es muy sencillo de usar y nos permite desarrollar casi, casi, casi como si tuviesemos un GC.

Nota: El runtime de Objective-C soporta también el uso de Garbage Collector. Pero como en iOS no se puede usar, no hablaré del GC de Objective-C. Además su uso está marcado como obsoleto en favor de ARC.

En esta serie de posts veremos tanto la gestión manual (MRC) como la automática (ARC) de memoria.

Desde el punto de vista de un desarrollador de C# debes quedarte con lo siguiente:

  1. Si usas ARC la forma de desarrollar será muy parecida a C#: vamos a crear objetos y nos despreocuparemos de liberar la memoria. ARC lo hará por nosotros.
  2. A diferencia de C++ que admite el paso por valor de objetos, en Objective-C se admite tan solo paso por referencia a través de punteros. Eso lo hace más parecido a C# (cuando se pasa un objeto no se pasa por valor, si no que se pasa una referencia a dicho objeto).

Bueno… lo dejamos aquí por el momento. En el siguiente post de la serie, más 😉

Saludos a todos!

WebApi–Recibir en un controlador un IEnumerable desde URL

Muy buenas!

En un proyecto en el que estoy trabajando ha surgido la necesidad de pasarle via GET una lista de ids con los que hacer algo. La acción del controlador FinishersController está declarada de la siguiente manera:

public IEnumerable<TrackingAndCompetitorDTO> GetByRaces(IEnumerable<int> id)

{

    return null;

}

Ahora viene el momento de llamar al controlador:

  • /api/Finishers/10,20,30 –> Devuelve un 404
  • /api/Finishers/10 –> Enlaza a al acción pero id es null
  • /api/Finishers/?id=10,20,30 –> Enlaza a la acción pero id es null
  • /api/Finishers/?id=10&id=20&id=30 –> Enlaza a la acción pero id es null
  • /api/Finishers/?id[0]=10&id[1]=20&id[2]=30 –> Enlaza a la acción pero id es null

Si tienes experiencia en ASP.NET MVC entenderás que las tres primeras fallen es comprensible (también fallarían en MVC). Pero las dos últimas en MVC funcionarían correctamente… ¿entonces por qué fallan en WebApi?

La forma en como se realiza el enlace de parámetros de la request hacia los controladores es totalmente diferente en WebApi que en MVC. Insisto: WebApi es otra cosa completamente distinta aunque luzca muy parecida a ASP.NET MVC y aunque vengan juntos. No des por supuesto nada de lo que sabes en ASP.NET MVC para WebApi. Algunas cosas funcionan igual, otras, completamente distinto.

En ASP.NET MVC el enlace desde la request hacia los controladores se realiza mediante los ValueProviders y los Model Binders. Los primeros son los encargados de inspeccionar la request (formdata, querystring, pathinfo, headers, …) y dejar los valores en un sitio común. Luego los model binders leen de “ese sitio común” y construyen los valores de los parámetros que el controlador recibe.

WebApi añade a estos dos conceptos, un tercero: los media type formatters. Bien, recuerda siempre la gran diferencia entre WebApi y MVC: En MVC se usa un buffer para guardar la petición (y la respuesta). Eso significa que los value providers pueden leer n veces el cuerpo de la petición sin que de error. En WebApi NO. WebApi es, por decirlo de algún modo, stream-based. Nuestros media type formatters reciben un stream y pueden leer de él una sola vez. Por lo tanto tan solo un media type formatter puede leer el cuerpo de la petición.

Pero ojo… he dicho que WebApi añade el concepto de media type formatters, porque en WebApi también se usan value providers y model binders. ¿Cuando? Pues para enlazar parámetros que no provienen del cuerpo de la petición (o sea, usualmente de la URL). Esa es la norma báscia:

  1. El parámetro no está en el cuerpo? Se enlaza vía un model binder
  2. El parámetro está en el cuerpo de la petición? Se enlaza via un media type formatter

Webapi hace ciertas asunciones sobre si un parámetro debe enlazarse via model binder o media type formatter. Básicamente: si es tipo simple se usará un model binder. Si es un tipo complejo se usará un media type formatter. Por lo tanto, por defecto nuestro parámetro IEnumerable<int> al NO ser un tipo simple se intenta enlazar mediante un media type formatter. De ahi que no se encuentren datos porque los media type formatters miran tan solo el cuerpo y en nuestro caso está vacío.

¿Y como podemos modificar este comportamiento? Pues bien:

  1. Si decoras un parámetro con [FromUri] indicas a WebApi que este parámetro vendrá en la URL
  2. Si decoras un parámetro con [FromBody] indicas a WebApi que este parámetro vendrá en el cuerpo de la petición
  3. Si decoras un parámetro con [ModelBinder] puedes especificar un Model Binder específico para tu parámetro. (De hecho [FromUri] deriva de [ModelBinder]).
  4. Y recuerda: El cuerpo de la petición tan solo puede leerse una vez. Por lo tanto si tu controlador recibe dos parámetros complejos tan solo uno puede ser procesado mediante un media type formatter (y venir en el cuerpo). El otro debe ser procesado mediante un model binder y venir en alguna otra parte que NO sea el cuerpo de la petición  (y estar decorado con [ModelBinder] o [FromUri]).

Bueno… ahora ya ves la solución a nuestro problema no? Basta con decorar el parámetro con [FromUri]:

public IEnumerable<TrackingAndCompetitorDTO> GetByRaces([FromUri] IEnumerable<int> id)

{

    return null;

}

Con esto estamos forzando a WebApi a que enlace este parámetro usando los value providers y model binders. Y ahora la URL

  • /api/Finishers/?id=10&id=20&id=30 –> Funciona correctamente.

Curiosamente la URL

  • /api/Finishers?id[0]=10&id[1]=20&id[2]=30 NO funciona, pero eso ya se debe a diferencias de como está implementado el Model binder de WebApi y el de MVC cuando tratan con colecciones…

Saludos!

WebApi–Devolver tipos anónimos en XML

Bueno… Honestamente: este post viene a colación de que se estuvo hablando por Linkedin de dedicar hoy (4 de Marzo) un post o algo a WebApi. He de decir que personalmente, no suelo planificar de que escribo. Es decir, tengo varias series abiertas de posts, montones de artículos en borrador y luego voy escribiendo cosas según me van viniendo.

WebApi es un tema que he tratado bastante en mi blog. Uno de los temas que NO he tratado y que era un buen candidato era la exposición de servicios OData usando WebApi. Pero Marc Rubiño se me adelantó y lo contó de manera fenomenal en su blog. Así que pensando temas sobre los que poder hablar al final he optado por este:

image

Este error se produce si haces algo como p. ej:

public class BeersController : ApiController

{

    // GET api/values

    public IEnumerable Get()

    {

        return new ArrayList() {new {Name = "ufo", Value = 10}, new {Age = 20, Name = "Gag"}};

    }

}

Es decir si devuelves un objeto anónimo (en mi caso estoy devolviendo una colección de objetos anónimos pero si devuelves uno solo ocurre lo mismo).

La primera opción es pensar que WebApi no soporta objetos anónimos. Pero es falso. WebApi, como tal, no tiene problema alguno en devolver objetos anónimos. Si llamo al mismo servicio pero usando una cabecera Accept application/json para que me devuelva el resultado en json:

image

En json funciona correctamente. Y es que el problema no está en WebApi en sí… Si no en el serializador de XML que WebApi usa.

Básicamente y resumiendo: El serializador de XML de WebApi no soporta objetos anónimos.

¿Y hay solución para ello?

¡Pues claro! Crearte tu propio serializador de XML y luego un media type formatter asociado que lo use.

Lo primero es eliminar el media type formatter de XML que viene por defecto. Para ello, en Application_Start:

config.Formatters.Remove(config.Formatters.XmlFormatter);

Con esto eliminamos el media type formatter de XML y por lo tanto WebApi deja de dar soporte a XML. Este media type formatter que viene por defecto utiliza o bien DataContractSerializer o bien XmlSerializer para serializar los datos y ninguno de los dos tiene soporte para tipos anónimos. Lo primero es crearnos un serializador de XML propio que tenga soporte para tipos anónimos.

Yo he usado uno (muy sencillo y nada “personalizable”) que he encontrado en http://stackoverflow.com/questions/2404685/can-i-serialize-anonymous-types-as-xml. Simplemente lo he completado para que tenga soporte para colecciones de elementos. El código del serializador es:

public static class CustomXmlSerializer

    {

        private static readonly Type[] WriteTypes = new[] {

            typeof(string), typeof(DateTime), typeof(Enum),

            typeof(decimal), typeof(Guid) };

 

        public static bool IsEnumerable(this Type type)

        {

            return type.GetInterface("IEnumerable") != null;

        }

 

        public static bool IsSimpleType(this Type type)

        {

            return type.IsPrimitive || WriteTypes.Contains(type);

        }

        public static XElement ToXml(this object input)

        {

            return input.ToXml(null);

        }

 

        public static XElement ToXml(this object input, string element)

        {

            if (input == null)

                return null;

 

            if (string.IsNullOrEmpty(element))

                element = "object";

            element = XmlConvert.EncodeName(element);

            var ret = new XElement(element);

 

            if (input != null)

            {

                var type = input.GetType();

                var props = type.GetProperties();

 

                var elements = from prop in props

                               let name = XmlConvert.EncodeName(prop.Name)

                               let val = prop.GetValue(input, null)

                               let value = prop.PropertyType.IsSimpleType()

                                    ? new XElement(name, val)

                                    : val.ToXml(name)

                               where value != null

                               select value;

 

                ret.Add(elements);

            }

 

            return ret;

        }

 

    }

El código es bastante simple no? Básicamente itera sobre todas las propiedades del elemento y usa Linq to XML para convertirlas a XML.

Una vez tenemos un serializador que nos soporta tipos anónimos, ha llegado el momento de crear un media type formatter que lo use. Recuerda que los media type formatters son las clases que usa WebApi para leer/escribir desde/el stream de la petición/respuesta.

En nuestro caso nuestro media type formatter soportará escritura solamente. Eso signfica que podremos devolver tipos anónimos en XML pero NO soportaremos la lectura de XML en las peticiones (es decir no aceptaremos peticiones cuyo cuerpo sea un XML (al menos no con este media type formatter)).

El código es realmente simple:

public class CustomXmlFormatter : BufferedMediaTypeFormatter

{

    public CustomXmlFormatter()

    {

        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));

        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));

    }

 

    public override bool CanReadType(Type type)

    {

        return false;

    }

 

    public override bool CanWriteType(Type type)

    {

        return true;

    }

 

    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)

    {

        using (var writer = new StreamWriter(writeStream))

        {

            WriteAny(writer, type, value);

        }

 

    }

 

    private void WriteAny(StreamWriter writer, Type type, object value)

    {

        if (type.IsEnumerable()) WriteCollection(writer, type, value);

        else WriteObject(writer, type, value);

    }

 

    private void WriteObject(StreamWriter writer, Type type, object value)

    {

        var xml = value.ToXml();

        writer.Write(xml.ToString());

    }

 

    private void WriteCollection(StreamWriter writer, Type type, object value)

    {

        var collection = value as IEnumerable;

        writer.Write("<collection>");

        foreach (var item in collection)

        {

            if (item != null)

            {

                WriteAny(writer, item.GetType(), item);

            }

        }

        writer.Write("</collection>");

    }

}

¡Listos! Simplemente redefinimos los métodos CanWriteType para indicar que podemos serializar cualquier tipo y CanReadType para indicar que NO podemos leer ninguno.

Luego redefinimos el método WriteToStream y usamos los métodos extensores definidos en nuestro serializador de xml propio para obtener el XML y escribirlo en el stream de salida.

Ahora tan solo nos queda registrar este media type formatter para que WebApi lo use:

config.Formatters.Add(new CustomXmlFormatter());

Y ahora ya estamos. Si ejecutamos de nuevo la llamada a nuestro servicio con una cabecera Accept que prefiera XML:

image

Resumen

  • WebApi usa el concepto de media type formatter para decidir que clase usar para serializar los datos devueltos por los controladores (también para leer los datos enviados a los controladores)
  • Un media type formatter básicamente se asocia a uno o varios tipos mime (eso se hace en el constructor de cada media type formatter)
  • El media type formatter por defecto que viene en WebApi para serializar XML usa DataContractSerializer o XmlSerializer y NO tiene soporte para tipos anónimos
  • Para habilitar el soporte de tipos anónimos debemos pues crearnos un media type formatter propio que use un serializador de XML que admita tipos anónimos.
  • Para JSON no es necesario hacer nada de esto: los tipos anónimos están soportados de serie.

Espero que te haya resultado interesante.

Saludos!

Como hacer seguros tus servicios WebApi

Buenas! Este post surge a raíz del comentario de Felix Manuel en mi post anterior Inyección de dependencias per-Request. En él Felix comentaba que le gustaría ver algo sobre autenticación y autorización de WebApi… así que vamos a ello.

Todo lo que comentaré en este post va destinado a servicios WebApi que queramos tener en internet. No hablaré nada de otros escenarios como intranets que pueden tener otras soluciones.

Vamos a partir del template de proyecto ASP.NET MVC4 – WebApi

AuthorizeAttribute

En ASP.NET MVC si queremos añadir seguridad a un controlador, basta con que usemos [Authorize] para decorar todas aquellas acciones que requieran seguridad.

¿Qué ocurre si aplicamos lo mismo a WebApi?

public class SecureController : ApiController

{

    [Authorize]

    public string GetSecure()

    {

        return "Acces granted!";

    }

}

Asegúrate de usar el AuthorizeAttribute que está en System.Web.Http, no el que está en System.Web.Mvc!

Con esto, si realizo una llamada GET a /api/secure obtengo un mensaje de error (recuerda que puedes recibirlo en json o xml dependiendo de la cabecera accept que mandes):

<Error><Message>Authorization has been denied for this request.</Message></Error>

Bien… parece que el filtro realiza su trabajo, pero ¿qué hace exactamente? Para ello echemos un vistazo a su código fuente. El método que realiza el trabajo es IsAuthorized que tiene un código como el siguiente:

IPrincipal user = Thread.CurrentPrincipal;

if (user == null || !user.Identity.IsAuthenticated)

{

    return false;

}

Bueno… pues parece que está claro: [Authorize] se limita a validar que haya un CurrentPrincipal que esté autorizado.

¿Así que la pregunta nos rebota: quien crea y coloca el IPrincipal autorizado?

Para verlo, realicemos una prueba: Vamos a crear un controlador nuevo con un método GET (para llamarlo fácilmente desde el navegador) para autenticarnos, usando FormsAuthentication (el mecanismo clásico de autenticación de ASP.NET).

public class AuthController : ApiController

{

    public string Get(string id)

    {

        FormsAuthentication.SetAuthCookie(id ?? "FooUser", false);

        return "You are autenthicated now";

    }

}

Vale, ahora puedes probar de realizar desde el navegador:

  1. Una llamada a /api/Auth/XXX (XXX nombre de usuario que quieras)
  2. Otra llamada a api/Secure y ver… como sigues sin estar autenticado.

La llamada  a FormsAuthentication lo que hace es colocar una cookie (llamada comúnmente ASPXAUTH) que es la cookie de autenticación de asp.net. Pero por alguna razón la estamos obviando. Bien, esta razón es que NO hemos definido modelo de seguridad en web.config. Si lo abres verás que hay la línea:

<authentication mode="None" />

Modificala para que sea:

<authentication mode="Forms" />

¡Y listos! Si repites el par de llamadas anterior, ahora verás como la llamada a /api/Secure si que te funciona, ya que ahora el proveedor de autenticación Forms utiliza la cookie y en base a ella crea un IPrincipal y lo autentica.

¿Qué, sencillo no? Pues no tanto…

Cuando usar y cuando no usar autenticación por Forms

Usar la autenticación Forms NO es mala idea si tus servicios WebApi van a ser utilizados tan solo desde el contexto de una aplicación web que antes haya autenticado al usuario. ¿Y por qué? Bueno… pues porque las cookies son algo muy del mundo web.

Pero si creas una API para ser usada en otros dispositivos o aplicaciones (p. ej. una aplicación nativa de móvil) usar cookies para autenticarnos es una mala idea, ya que entonces obligas a quien usa tus servicios a que ponga código para leer las cookies recibidas y enviarlas de nuevo. Eso, si usas un navegador, lo hace el navegador automáticamente.

Así que lo dicho: si tus servicios WebApi van a ser utilizados tan solo dentro de una aplicación web (p. ej. para darte soporte a llamadas Ajax) puedes usar el mecanismo que acabamos de ver. En este caso, habitualmente, los controladores WebApi se despliegan en el mismo proyecto que los de ASP.NET MVC (si no recuerda que deberás lidiar con cross-domain). Y quien autentica al usuario (o sea quien tiene la llamada a FormsAuthentication.SetAuthCookie) es un controlador de MVC (el que responde al formulario de Login, claro). Y los controladores WebApi los tienes decorados tan solo con el [Authorize].

Pero vamos a olvidarnos de este escenario y planteemos otro: estás creando simplemente una API. El consumidor de esta API va a ser una aplicación de móvil (p. ej.) o dicho de otro modo, no va a ser un browser.

Entonces NO debemos usar autenticación por Forms y debemos buscar otros mecanismos. La pregunta es… ¿Cuales?

Autenticación básica

Bueno… exploremos esta opción. La autenticación básica de HTTP es muy sencilla. Aunque tiene un flujo que empieza por mandar un 401 con una cabecera específica todo eso lo obviaremos (eso es porque los navegadores sepan que hay un proceso de autenticación pero en nuestro caso el cliente no es un navegador).

Asi, si nos centramos en como es una petición autenticada que use autenticación básica, es muy sencillo: Tiene una cabecera Authorization con este formato:

Authorization: Basic username:password

La única salvedad es que username:password se envía codificado en BASE64.

Vale… ¿y como implementamos eso en WebApi? Pues hay varias maneras, p. ej. nos podríamos crear un filtro de autorización propio:

public class BasicAuthorizeAttribute : AuthorizationFilterAttribute

{

    public override void OnAuthorization(HttpActionContext actionContext)

    {

        var headers = actionContext.Request.Headers;

        if (headers.Authorization != null && headers.Authorization.Scheme == "Basic")

        {

            try

            {

                var userPwd = Encoding.UTF8.GetString(Convert.FromBase64String(headers.Authorization.Parameter));

                var user = userPwd.Substring(0, userPwd.IndexOf(‘:’));

                var password = userPwd.Substring(userPwd.IndexOf(‘:’) + 1);

                // Validamos user y password (aquí asumimos que siempre son ok)

            }

            catch (Exception)

            {

                PutUnauthorizedResult(actionContext, "Invalid Authorization header");

            }

        }

        else

        {

            // No hay el header Authorization

            PutUnauthorizedResult(actionContext, "Auhtorization needed");

        }

    }

 

    private void PutUnauthorizedResult(HttpActionContext actionContext, string msg)

    {

        actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)

        {

            Content = new StringContent(msg)

        };

    }

}

Nota: Para realizar tareas de autorización (como este caso) debemos usar un filtro de autorización. No uses para ello un filtro de acción (es decir, no derives de ActionFilterAttribute y redefinas OnActionExecuting). La razón es que los filtros de autorización se ejecutan antes que los filtros de acción, ya que precisamente su tarea es esa: autorizar la llamada a una acción. No está de más que te descargues el poster con el ciclo de vida de una petición WebApi de http://www.microsoft.com/en-us/download/details.aspx?id=36476

Ahora tan solo debemos decorar la acción Secure del controlador con [BasicAuthorize] en lugar de [Authorize] y ya tenemos la autenticación básica implementada (para pasar de cadena a base64 puedes usar cualquiera de las páginas que hay por ahí que lo hacen como http://www.motobit.com/util/base64-decoder-encoder.asp):

image

Si eliminar el tag Authorization verás como la respuesta pasa a ser un 401.

Por supuesto, la autenticación básica de HTTP es tan insegura que tan solo debería usarse sobre HTTPS.

Vale… pero quizá te estás preguntando si tenemos más alternativas que usar un filtro de autorización para validar si una petición está autorizada. Y la respuesta es que sí. Tenemos al menos dos más:

  1. Usar un Message Handler
  2. Usar un módulo de autenticación de ASP.NET

¿Te parece si exploramos ambas?

Usando un Message Handler

Los Message Handlers se ejecutan incluso antes que los filtros de autorización. Es más, se ejecutan incluso antes de que el pipeline de WebApi seleccione un controlador así que son un lugar propicio para poner código de autorización.

Los Message Handlers tienen la potestad de generar ellos mismos un resultado y entonces todo el resto de la pipeline de WebApi es eliminada. Es decir es posible que un Message Handler intercepte una petición, genere un resultado y entonces esta petición no será transferida al controlador a la cual debería haber llegado.

Esto puede parecer que hace que los Message Handlers sean un buen sitio para autorizar peticiones y lo son, pero NO son un buen sitio para rechazar peticiones no autorizadas. Me explico: sigamos con nuestro ejemplo de autenticación básica.

Si usas un Message Handler y rechazamos todas las peticiones que NO tengan la cabecera Authorize entonces tendremos un problema si necesitamos tener alguna parte de la API pública. Un Message Handler se ejecuta siempre. Para todas las peticiones.

Si quieres usar un Message Handler para autorización lo que debes hacer no es rechazar las peticiones que estén autorizadas (en nuestro caso que no tengan la cabecera Authorize). No. En su lugar debes autorizar aquellas peticiones válidas. ¿Como? Colocando un IPrincipal en el Thread. Y luego, en los controladores utilizas [Authorize].

Veamos un ejemplo rápido:

public class BasicAuthMessageHandler : DelegatingHandler

{

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,

        CancellationToken cancellationToken)

    {

        var headers = request.Headers;

        if (headers.Authorization != null && headers.Authorization.Scheme == "Basic")

        {

            var userPwd = Encoding.UTF8.GetString(Convert.FromBase64String(headers.Authorization.Parameter));

            var user = userPwd.Substring(0, userPwd.IndexOf(‘:’));

            var password = userPwd.Substring(userPwd.IndexOf(‘:’) + 1);

            // Validamos user y password (aquí asumimos que siempre son ok)

            var principal = new GenericPrincipal(new GenericIdentity(user), null);

            PutPrincipal(principal);

        }

 

        return base.SendAsync(request, cancellationToken);

    }

 

    private void PutPrincipal(IPrincipal principal)

    {

        Thread.CurrentPrincipal = principal;

        if (HttpContext.Current != null)

        {

            HttpContext.Current.User = principal;

        }

    }

}

Este Message Handler crea y coloca un GenericPrincipal si la cabecera Authorize está presente. Luego en el controlador debemos usar [Authorize] para aquellas acciones que requieran de usuario autenticado.

Acuerdate de registrar el Message Handler desde Application_Start:

config.MessageHandlers.Add(new BasicAuthMessageHandler());

Por lo tanto estamos usando una combinación entre un Message Handler y un filtro de autorización (Authorize).

Usando un módulo de autenticación

Bien… exploremos esta otra alternativa. Ahora vamos a usar un módulo de autenticación (un HttpModule) para realizar las mismas tareas que realiza el Message Handler, es decir para crear un IPrincipal.

¿Y qué diferencias hay entre usar un HttpModule o un Message Handler? Pues buena pregunta, básicamente las siguientes:

  1. Un HttpModule es algo específico de IIS. No lo puedes usar en aplicaciones WebApi que no estén hospedadas en IIS. Por otro lado un Message Handler es algo propio de WebApi.
  2. Un HttpModule ve todas las peticiones que estén dirigidas al pipeline de ASP.NET. Sean peticiones de WebApi o no. Un Message Handler tan solo ve las peticiones WebApi.
  3. Un HttpModule se ejecuta antes en el pipeline que un Message Handler. De hecho se ejecuta antes que cualquier parte de WebApi.

Por norma general, es preferible usar un HttpModule si sabes que vas a hospedar tu WebApi siempre en un IIS. Si no, si quieres tener la posibilidad de hospedar tu WebApi en otros procesos entonces usa un Message Handler.

¿Listo para nuestro módulo de autenticación? Aquí lo tienes:

public class BasicAuthModule : IHttpModule

{

     public void Init(HttpApplication context)

     {

         context.AuthenticateRequest += OnAuthenticateRequest;

     }

 

     private void OnAuthenticateRequest(object sender, EventArgs e)

     {

         var application = (HttpApplication)sender;

         var request = new HttpRequestWrapper(application.Request);

 

         var headers = request.Headers;

         var authData = headers["Authorization"];

         if (!string.IsNullOrEmpty(authData))

         {

             var scheme = authData.Substring(0, authData.IndexOf(‘ ‘));

             var parameter = authData.Substring(scheme.Length).Trim();

             var userPwd = Encoding.UTF8.GetString(Convert.FromBase64String(parameter));

             var user = userPwd.Substring(0, userPwd.IndexOf(‘:’));

             var password = userPwd.Substring(userPwd.IndexOf(‘:’) + 1);

             // Validamos user y password (aquí asumimos que siempre son ok)

             var principal = new GenericPrincipal(new GenericIdentity(user), null);

             PutPrincipal(principal);

         }

     }

 

     public void Dispose()

     {

 

     }

 

     private void PutPrincipal(IPrincipal principal)

     {

         Thread.CurrentPrincipal = principal;

         if (HttpContext.Current != null)

         {

             HttpContext.Current.User = principal;

         }

     }

}

Puedes ver como el código es muy parecido al del Message Handler. Ahora debemos registrarlo. Los HttpModules se registran en el web.config, dentro de la sección modules de system.webServer:

<system.webServer>

  <modules>

    <add name="BasicAuthHttpModule"

      type="MvcSecureDemo.BasicAuthModule, MvcSecureDemo"/>

  </modules>

</system.webServer>

La situación es la misma que teníamos en el caso del Message Handler: en los controladores debemos usar [Authorize] para proteger las acciones que requieran usuarios autenticados.

Más allá de autenticación básica

Vale… hemos explorado como securizar nuestros servicios WebApi (a través de filtros de autorización, Message Handlers y HttpModules). Lo hemos hecho a partir de la autenticación básica de HTTP porque es muy sencilla y así el código no queda liado. 😉

Pero autenticación básica NO es un buen mecanismo. No lo es, a menos que uses HTTPS, ya que el login y el password viajan en texto plano (recuerda que Base64 no es cifrado).

Bien, ¿qué debéríamos hacer si no tenemos HTTPS? Una solución pasa por encriptar realmente el login y el password. Esto sigue teniendo un riesgo, tan pequeño como seguro sea nuestro algoritmo de encriptación y segura esté la clave que usemos).

Exploremos otra alternativa, otra que signifique que ni el login ni el password viajan por la red. Nadie con un sniffer será capaz de saber nuestra password escuchando los mensajes que nos intercambiamos con el servidor… Veamos que deberíamos hacer.

Partamos de la suposición de que tanto el cliente (una aplicación móvil p. ej.) y el servidor comparten un código, llamésmole código de acceso. Da igual como lo han compartido (p. ej. a través de un email). Lo importante es que lo tienen.

Entonces básicamente si el cliente adjunta este código en una cabecera (sigamos suponiendo la misma cabecera Authorization) la llamada se considera autenticada y en caso contrario se considera válida. Este código (insisto: obtenido previamente) identifica al cliente (la aplicación móvil) y al usuario de dicho cliente, por lo que adjuntando este código una aplicación puede hacer peticiones en nombre del usuario.

Vale, no parece que hayamos progresado mucho verdad: alguien con un sniffer pilla nuestra petición y ya tiene el código. Muy seguro el sistema no parece.

Bueno… sigamos suponiendo. Sigamos suponiendo que además de este código, tanto cliente como servidor comparten otro código. Un código secreto. Lo de secreto viene porque este segundo código jamás viajará por la red. Nunca. Lo comparten al inicio de los tiempos (p. ej. por mail) y luego el cliente se lo guarda y el servidor también.

Ahora lo que debe hacer el cliente es mandar la petición pero usará el código secreto para generar un hash del código de acceso. Y la cabecera Authorization contendrá este hash. Cuando el servidor recibe una petición del cliente debe:

  • Calcular el hash del código de acceso del cliente usando el código secreto (que ambos comparten)
  • Si el resultado es el mismo que ha enviado el cliente, la petición se considera autenticada.

Vale… hay un problemilla ahora. El código secreto debe ser distinto por cada cliente, pero si tan solo recibimos en la cabecera Authorization el hash del código de acceso… ¿como sabemos qué código secreto debemos usar para calcular el hash?. Es decir, como sabemos de qué cliente es la petición.

Pues nada. Hacemos que cliente y servidor comparten otro elemento: un identificador de cliente. Ahora el cliente en la cabecera Authorization mandará su código identificador y el hash de su código de acceso (calculado con su código secreto). Cuando el servidor recibe la petición, sabe de que cliente es (por el identificador de cliente de la cabecera Authorization) y podrá usar el código secreto de este cliente para calcular el hash del código de acceso de este cliente y validar que sea el mismo que el clienté envía.

¿Te parece seguro el sistema ahora? No lo es en absoluto. Alguien que pille una petición podrá hacer lo que quiera, porque tendrá el hash del código de acceso. Estamos igual que al principio… pero a un paso de la solución.

El problema de que si nos pillan una petición luego ya nos puedan suplantar siempre es porque estamos calculando un hash de algo que jamás se modifica: el código de acceso. Porque en lugar de calcular un hash de dicho código no calculamos un hash de una cadena que esté compuesta de:

  1. La URL de destino
  2. Los datos en query string/formdata
  3. El código de acceso

Los datos 1 y2 son variables (distintos por cada petición que hagamos). Así cada petición tendrá un hash distinto. Cuando el servidor reciba la petición calculará esta cadena con la URL, la query string/formdata y el código de acceso del cliente y usará el código secreto del cliente para calcular el hash. Si coinciden la petición queda autenticada.

Ahora si alguien nos pilla una petición con un sniffer, tan solo podrá hacer una cosa: enviarla otra vez al servidor. No podrá modificarla, porque si lo hace (p. ej. modifica la querystring para cambiar un parámetro) automáticamente el hash pasa a ser inválido. Y no puede construir un hash nuevo porque no tiene acceso al código secreto.

Así pues un hacker nos puede pillar peticiones y puede ver su contenido. Hasta puede guardarlas y reenviarlas al servidor más adelante. Pero NO puede crear peticiones falsas en nuestro nombre.

Vayamos un paso más allá. ¿Por qué no adjuntamos el tiempo en que se realiza la petición? Es decir el cliente añade en una cabecera la fecha y hora en que realiza la petición. Y usa este dato también para calcular el hash. Ahora el servidor puede validar que la fecha/hora que envía el cliente sea (aproximadamente) la actual. Si el servidor recibe una petición de un cliente con una fecha/hora de hace 4 minutos, la puede aceptar pero si es de hace 1 hora la puede rechazar, ya que seguramente es una petición interceptada, guardada y mandada luego. Dado que la fecha/hora se usa también para calcular el hash, el hacker que nos intercepte la petición no puede falsear este dato.

Incluso podríamos hacer algo más: añadir un número (llamésmole nonce) de secuencia. La idea es que dos peticiones del mismo cliente jamás pueden repetir el nonce. Por supuesto el nonce se manda en otra cabecera y también se usa para calcular el hash. Si ahora un hacker nos intercepta la petición y la intenta mandar al cabo de 3 minutos… será rechazada porque este nonce ya ha sido usado.

Ahora estamos protegidos de todos los ataques, excepto de un Man-in-the-middle. Ojo, no tenemos privacidad (tanto las peticiones como las respuestas van sobre HTTP en texto llano), pero nuestras credenciales están seguras y nadie puede crear peticiones en nuestro nombre ni guardarse peticiones válidas y enviarlas más adelante. Si requerimos privacidad y protección contra ataques tipo Man-in-the-middle entonces lo más rápido es usar HTTPS.

Por supuesto este sistema que he descrito, no me lo he inventado yo. Este sistema lo inventó Blain Cook y le dio el nombre de oAuth. Lo que he descrito aquí es (rápido y mal, por supuesto) el flujo básico de oAuth 1.0.

Las ventajas de oAuth son que en ningún momento las credenciales del usuario circulan por la red y que ofrece un buen balance de seguridad siempre y cuando el código secreto no se vea comprometido. Es pues una muy buena opción para proteger tus servicios WebApi.

Y por supuesto, usar otros mecanismos de autenticación no modifica en nada lo dicho en este post, tan solo “complica” el código que has de poner en tu filtro de autorización, message handler o HttpModule.

Un saludo!

Objective-C para desarrolladores de C# (i)–Introducción

Muy buenas! Con este post inicio una serie de posts (como siempre, ni idea de cuantos van a ser) dedicado especialmente a desarrolladores de C# que quieran empezar con Objective-C. No soy un experto en Objective-C ni esta serie pretende que te conviertas en un experto en este lenguaje. Tampoco es un tutorial de Objective-C. Es simplemente una ayuda para todos aquellos desarrolladores con un background de C# y .NET que tengan curiosidad por ver como es el lenguaje de la manzana.

A lo largo de esta serie intentaré tocar el máximo número de temas y eso incluirá:

  • Lenguajes: Vamos a comparar las características intrínsecas de ambos lenguajes. Por intrínsecas me refiero a las características que no dependen de ninguna API o librería externa como sintaxis, tipos básicos, etc…
  • Herramientas: Por mucho que sean posts de Objective-C y de C# ambos lenguajes están muy enfocados a plataformas muy concretas y se suelen usar con herramientas muy concretas. Así que hablaré de XCode y de Visual Studio. Pero eso no quita que existan otras herramientas para ambos lenguajes.
  • Plataforma: Los lenguajes, si nos ceñimos a su definición, son agnósticos de plataforma. Pero vamos a terminar hablando de plataforma, porque todo lenguaje necesita una que le de soporte. En el caso de C# tenemos la BCL y luego todo .NET. En Objective-C tenemos Foundation y luego Cocoa y las apis de iOS (no hablaré de desarrollo para MacOS porque no tengo ni idea). Así que, en algún momento, compararemos las plataformas asociadas a cada lenguaje. Por supuesto esta comparación no será, porque no lo pretende porque no puede, ser una comparación exhaustiva.

Todos los posts de la serie estarán escritos des del punto de vista de alguien que viene (y por lo tanto conoce) el mundo de C# y .NET. Esta serie no busca en ningún momento un ganador. Por eso que nadie busque en las comparaciones vencedores y perdedores. Eso queda en el juicio de cada uno.

Y finalmente… la pregunta del gritón de dólares: ¿Necesito un ordenador de Cupertino para seguir la serie?

Pues para seguirla toda, toda, toda pues obviamente sí. Cuando hablemos de XCode o de Cocoa vas a necesitar un Mac si quieres “hacer ejemplos en vivo”.

De todos modos doy por supuesto que si te ha picado la curiosidad por Objective-C es que te estés planteando el desarrollar para iOS, por lo que necesitarás un Mac tarde o temprano 😛 Pero, es posible hacer muchos de los ejemplos que presentaré en un PC con Windows. Existe el runtime de Objective-C para Windows, por lo que si lo que pretendes es simplemente trastear con Objective-C podrás hacerlo desde Windows. Obviamente con limitaciones.

Luego ya podrás decidir si prefieres comprarte un Mac o bien prefieres contactar con Juan Fco. Miranda quien te guiará por los sinuosos caminos del Hackintosh.

Instalación de Objective-C en Windows

Bueno, el primer paso es ir a la página de descargas para Windows de GNUStep y descargarte:

  1. GNUstep MSYS System
  2. GNUstep Core
  3. GNUstep Devel

Luego instalatelos en este mismo orden. Yo por ejemplo los tengo instalados en D:GNUStep

GNUStep consiste en una serie de herramientas, como gcc para compilar Objective-C y también tiene ports de parte de la plataforma (está Foundation y parte de Cocoa implementado).

GNUStep es para hombres y no viene con ningún IDE ni nada parecido. Aunque técnicamente no necesitas ninguno ya que GNUStep te habrá instalado make.exe. Yo no conozco ningún IDE de Objective-C para Windows por ahí (personalmente no uso Objective-C bajo Windows).

Para probar si GNUStep está bien instalado vamos a realizar nuestro HelloWorld.

Abre tu editor de texto favorito y crea un fichero llamado HelloWorld.m con el siguiente código:

#import <Foundation/Foundation.h>
int main (void)
{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSLog (@"Hello, World!");
        [pool drain];
        return;
}

Guardalo como HelloWorld.m (la extensión .m es la que se suele usar para crear archivos Objective-C)

Ahora nos toca usar gcc.exe para compilar este archivo. Ello deberemos hacerlo desde línea de comandos. Abres una línea de comandos y te vas donde tengas el archivo HelloWorld.m y tecleas (todo en una misma línea):

gcc HelloWorld.m -I D:/GNUstep/GNUstep/System/Library/Headers -L D:/GNUstep/GNUstep/System/Library/Libraries -fconstant-string-class=NSConstantString -o HelloWorld.exe -lobjc -lgnustep-base

Las opciones que estamos usando son las siguientes:

  • -I <path_includes>: Path raíz de los archivos de cabecera
  • -L <path_libraries>: Path raíz de los archivos de librería
  • -fconstant-string-class <clase>: Nombre de la clase a usar cuando haya constantes string.
  • -o <fichero>: Nombre del fichero de salida
  • -lobjc: Para enlazar con la librería de objective C
  • -lgnustep-base: Para enlazar con la librería de GnuStep

Esto te debería compilar y generar el HelloWorld.exe… Si es así, ya estás listo para empezar a programar con Objective-C bajo Windows 😉

En sucesivos posts veremos como compilar usando XCode (por si tienes un Mac) y empezaremos a ver las diferencias entre Objective-C y C#).

Nos vemos!