Vende a la nube capacidad de proceso de tu móvil

imageIndudablemente, hoy en día llevamos en el bolsillo ordenadores en miniatura mucho más potentes de lo que eran los equipos de escritorio hace unos años. Cualquier smartphone razonablemente actualizado es capaz de funcionar a más de 1Ghz y cuenta con varios gigabytes de memoria RAM, y, sin embargo, toda esta potencia está infrautilizada la mayor parte del tiempo.

Por otro lado, tampoco se puede dudar ya de la entrada de la nube en nuestras vidas. Cada vez desplazamos más capacidad de almacenamiento y proceso a infraestructuras fiables y escalables como las ofrecidas por proveedores como Microsoft, Amazon, Google, Oracle y otros, con un coste más que razonable. Esto, sin embargo, presenta un reto a medio y largo plazo: ¿serán las infraestructuras de estos proveedores suficientes como para soportar el crecimiento exponencial en servicios demandados por los usuarios?

Conscientes de ello, el grupo de trabajo Stratus de Microsoft Research remitió hace unos meses al IETF (Internet Engineering Task Force) una propuesta para la estandarización de un conjunto de tecnologías y protocolos destinados a “trocear” la carga de procesos soportada por la nube y distribuirlos para que sean ejecutados de forma paralela por los móviles de los usuarios aprovechando los momentos de inactividad de estos dispositivos.

Como idea no se trata de algo nuevo, hace años que existen a otros proyectos de computación voluntaria en grid como SETI@HOME (proyecto de la universidad de Berkeley para la búsqueda de vida extraterrestre), o Climateprediction.net (cálculo de predicciones meteorológicas), la novedad es llevar este concepto al mundo móvil, y enfocarlo con un ánimo más lucrativo para los implicados.

Imaginad el escenario: más de mil millones de smartphones en el mundo ofreciendo una pequeña parte de la potencia de sus terminales tendríamos el equivalente a un superordenador trabajando a una frecuencia de decenas o cientos de zettahercios (billones de gigahercios o 1021 Hz), con una potencia de cálculo que mediríamos en millones de Petaflops (muchos miles de billones de operaciones por segundo, poco más o menos). Y eso que no estamos contando con otros dispositivos susceptibles de ser aprovechados para el mismo fin, como equipos de escritorio, tablets, o incluso televisores.

Y lo mejor es que los tres factores que influyen en este concepto seguirán creciendo de forma espectacular: el número de terminales inteligentes, su capacidad de proceso, y la velocidad de las comunicaciones móviles. Se trata, por tanto, de una apuesta de muy largo recorrido y con una capacidad de escalado sin precedentes. El único secreto es saber cómo dividir el trabajo en unidades de computación distribuibles y ejecutables en paralelo, enviarlas a los terminales, sincronizar sus respuestas y hacer que los usuarios se involucren. ¿Fácil, eh? 😉

Pues ya lo han solucionado. CloudSlice Consortium, el organismo que promueve los estándares y buenas prácticas a las tecnologías emanadas desde este estándar, ya ha dado el visto bueno a la nueva oleada de dispositivos móviles basados en Windows Phone, iOs y Android, que vendrán equipados con la tecnología AzureSlice, y permitirá a los usuarios aprovechar su capacidad de proceso sobrante para soportar procesos distribuidos de Azure, obteniendo ingresos que pueden llegar a ser nada despreciables. Esta tecnología, por supuesto, no influye en la operativa normal del teléfono y podemos seguir usándolo normalmente; la única diferencia es que cuando no lo estemos utilizando éste estará realizando trabajos para la nube.

imageDe hecho, Movistar España y todas sus filiales hispanas han comenzado a comercializar el servicio Ur’Azure,  mediante el cual los usuarios no pagarán nada por sus llamadas ni comunicaciones desde el móvil sólo a cambio de tener instalado en sus dispositivos este pedacito de nube, es decir, el software para ejecutar los trabajos encomendados desde la central de coordinación de Azure.

También es posible descargar e instalar el software AzureSlice desde los respectivos markets, crearse una cuenta y comenzar a generar ingresos en los tiempos de inactividad de nuestros dispositivos. Aunque el volumen de ingreso depende del tiempo que cedamos a la nube, se estima que un usuario medio podría generar en torno a los 70-90$/mes, lo cual no está nada mal, eh?

Los inconvenientes de esta tecnología están siendo también afrontados por el Consorcio CloudSlice, y prometen interesantes novedades. Por ejemplo, se está trabajando en la creación de un software que permita cargar las baterías de los dispositivos móviles aprovechando la señal wi-fi o 3G, o en un adaptador universal de refrigeración por agua, de forma que se rompan las limitaciones físicas inherentes a este tipo de terminales.

Ya lo dijeron los Mayas, estamos viviendo el cambio a una nueva era, ¿a qué esperas para subirte? 

[Actualizado 29/12]
Nota para despistadillos: obviamente la noticia no es real, se trata simplemente de una broma del Día de los Inocentes. Podéis dejar de llamar a Movistar para contratar el servicio y guardar los móviles que habéis sacado del cajón para ganar dinero con esta iniciativa, porque de momento no va a poder ser ;-D

Publicado en Variable not found.

Validación en cliente de campos ocultos en ASP.NET MVC

 

ASP.NET MVCEn formularios ASP.NET MVC, por defecto los campos ocultos no son validados en cliente. Es decir, aunque estos campos hayan sido generados usando los helpers e incluyan atributos con las restricciones, no serán tenidos en cuenta por jQuery validate a la hora de validar los datos del formulario antes de enviarlos al servidor.

Así, si tenemos una clase del Modelo con una propiedad como la siguiente:

1
2
3
[Required(ErrorMessage="Required")]
[StringLength(3, ErrorMessage="Max. {1} chars")]
public string Name { get; set; }

e introducimos en la vista un código tal que este:

1
@Html.HiddenFor(model => model.Name)

El resultado enviado al cliente será:

1
2
3
4
5
<input type="hidden"
       id="Name" name="Name" value=""
       data-val="true"
       data-val-length="Max. 3 chars" data-val-length-max="3"
       data-val-required="Required"/>

Y, como comentaba anteriormente, a pesar de que el tag <input> contiene todos los atributos, este campo no será validado.

Tampoco lo será si el campo no es visible porque se haya ocultado mediante CSS, ya sea él mismo o alguno de sus padres en el DOM. En el siguiente ejemplo, el cuadro de texto para la propiedad Name tampoco será validado en cliente:

1
2
3
4
<div style='display: none'>
   ...
   @Html.TextBoxFor(model=>model.Name)
</div>

Este comportamiento, aunque puede parecer bastante lógico, a veces se interpone en nuestro camino, por ejemplo cuando usamos un campo hidden para almacenar valores obtenidos desde script, y que queremos enviar al servidor junto con el resto de campos del formulario:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Html.HiddenFor(model => model.Name)
<span id="currentName"></span>
<button id="selectName">Select name</button>
...
<script>
    $(function() {
        $("#selectName").click(function () {
            // Get the name using javascript
            var name = prompt("Please enter the name");
            $("#Name").val(name);
            $("#currentName").text(name);
            return false;
        });
    });
</script>

Para cubrir estos casos, jQuery Validate, entre sus múltiples settings, permite especificar mediante un selector qué campos deben ser ignorados cuando se realice la validación. Esto se define en la opción ignore y defecto su valor es “:hidden”, lo cual es el motivo de que sean ignorados:

  • los campos hidden,
  • los que tengan la propiedad CSS display igual a none,
  • aquellos que tengan ancho y alto cero,
  • y aquellos cuyos padres en el DOM sean invisibles según estos mismos criterios.

El valor por defecto de ignore puede ser modificado simplemente introduciendo la siguiente porción de scripts de forma que se ejecute tras cargar la biblioteca jQuery Validate:

1
$.validator.setDefaults({ ignore: null });

Con esa simple línea ya se validarán todos los campos del formulario, independientemente de su visibilidad.

Por último, comentar que ignore puede ser también interesante si en algún momento deseamos desactivar la validación para un campo concreto, o un grupo de ellos, siempre que podamos referenciarlos mediante un selector jQuery:

1
2
3
4
5
// Do not validate the fields #Name and #Age
// when a condition is satisfied
if(condition) {
   $('form').data('validation').settings.ignore = '#Name,#Age';
}

En fin, un truquillo en el algún momento nos puede venir bien tener mano.

Publicado en: Variable not found.

Errores de ASP.NET MVC 4 en distintos idiomas

Algunos mensajes que genera ASP.NET MVC utilizan el idioma en el que hayamos instalado el framework. Por ejemplo, si hemos descargado la versión en inglés de MVC 4 y estamos usando en sistema operativo en español, podemos encontrarnos con textos de error como los mostrados en la siguiente captura de pantalla:

Los textos en español son generados por las restricciones impuestas por los tipos de datos y las anotaciones (data annotations) que tengamos definidas para ellos. Dado que éstas pertenecen al framework .NET, normalmente tendremos instalados los recursos de nuestro idioma, y serán mostrados en el mismo debido a que es lo que estará indicado en las opciones culturales del hilo que procesa la petición.

Sin embargo, los textos que vemos en inglés son generados desde el propio ASP.NET MVC, por lo que aparecerán en el idioma en el que tengamos instalado el framework. Lo mismo ocurre con los mensajes de error que aparecen en la YSOD (“Pantalla amarilla de la muerte”), que normalmente nos los encontraremos en inglés.

Para solucionarlo de forma rápida, simplemente tenemos que descargar a través de Nuget  el paquete de idioma que nos interese, lo cual introducirá el ensamblado satélite con los recursos localizados en la carpeta de binarios.

La instalación, como siempre que utilizamos Nuget (¿recordáis cómo era la vida sin él? ;-)), es inmediata:

1
2
3
4
5
6
7
8
9
10
11
12
PM> Install-Package microsoft.aspnet.mvc.es
Attempting to resolve dependency 'Microsoft.AspNet.Mvc (= 4.0.20710.0)'.
Attempting to resolve dependency 'Microsoft.AspNet.WebPages (≥ 2.0.20710.0 && < 2.1)'.
Attempting to resolve dependency 'Microsoft.Web.Infrastructure (≥ 1.0.0.0)'.
Attempting to resolve dependency 'Microsoft.AspNet.Razor (≥ 2.0.20710.0 && < 2.1)'.
You are downloading Microsoft.AspNet.Mvc.es from Microsoft, the license agreement to which
Check the package for additional dependencies, which may come with their own license agreement(s).
Your use of the package and dependencies constitutes your acceptance of their license agreements.
If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'Microsoft.AspNet.Mvc.es 4.0.20710.0'.
Successfully added 'Microsoft.AspNet.Mvc.es 4.0.20710.0' to MvcApplication8.

De esta forma, ya los mensajes aparecerán traducidos al idioma especificado por la cultura del hilo de ejecución:

Culture: es-ES Culture: en-US

image

Obviamente, podemos instalar en el proyecto tantos paquetes de idioma como necesitemos 🙂

En fin, un pequeño truquillo que espero que os sea útil.

Publicado en: Variable not found.

Enums con desplegables automáticos en MVC

Si hay algo que me gusta de ASP.NET MVC es la cantidad de fórmulas que ofrece para aumentar nuestra productividad. Prácticamente cualquier código que estemos hartos de repetir una y otra vez puede ser encapsulado y reutilizado usando los puntos de extensión que nos proporciona el framework.

Hoy vamos a ver una solución a un problema al que seguro nos hemos enfrentado cientos de veces: la edición en formularios de propiedades de tipo enum.

1. El escenario

Imaginad que tenemos dos enumeraciones como las siguientes:

1
2
3
4
5
6
7
8
9
public enum Color
{
    Black, Blue, Red, Green
}
 
public enum Language
{
    English, Spanish, Italian, Portuguese
}

Usadas una clase del Modelo tal que:

1
2
3
4
5
6
public class Contact
{
    public string Name { get; set; }      
    public Language MainLanguage { get; set; }
    public Color? FavouriteColor { get; set; }
}

Y, a continuación, queremos crear un formulario de edición para la misma, con el código:

1
2
3
4
5
6
<h2>Edit contact</h2>
@using(Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="Send" />
}

imageComo era de esperar, el resultado una vez en ejecución es algo similar a lo que podemos ver en la captura de pantalla de la derecha.

Las propiedades MailLanguage y FavouriteColor, a pesar de ser enumeraciones, muestran como control de edición un simple cuadro de texto en el que podemos introducir cualquier cosa.

Y dado que son enum y podemos conocer sus valores de antemano, ¿no sería más lógico que la edición de estas propiedades se realizaran utilizando desplegables? 

2. Editor template para enums

Sin duda, la fórmula más sencilla y reutilizable para conseguir el objetivo que pretendemos es crear una plantilla de edición personalizada para las enumeraciones.

Como seguro sabréis, los editor templates proporcionan un mecanismo para generar controles de edición específicos para tipos de datos; podemos tener un editor para propiedades de tipo string (p.e., un cuadro de texto), de tipo DateTime (p.e., un cuadro de texto con un date picker), etc. Lo único que hay que hacer es crear en la carpeta /Views/Shared/EditorTemplates vistas parciales con el nombre del tipo de datos para el que se desea crear el editor (string.cshtml, datetime.cshtml, etc.).

Por tanto, probemos introduciendo el siguiente código en /Views/Shared/EditorTemplates/Enum.cshtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@model Enum
@{
    var isRequired = this.ViewData.ModelMetadata.IsRequired;
 
    var type = this.ViewData.ModelMetadata.ModelType;
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        type = type.GenericTypeArguments[0];
    }
 
    var values = Enum.GetValues(type);
    var items = (from object value in values
                 select new SelectListItem
                            {
                                Text = Enum.GetName(type, value),
                                Value = value.ToString()
                            });
}
@Html.DropDownListFor(m=>m, items, isRequired ? "Select...": "(None)")

Como se puede observar, prácticamente sólo hacemos tres cosas:

  • En primer lugar, determinamos la obligatoriedad de la propiedad a editar observando los metadatos del modelo.  
  • A continuación, creamos una lista de elementos de tipo SelectListItem recorriendo los valores disponibles en la enumeración. Observad que es necesario comprobar si el tipo que nos está llegando es anulable (Nullable<TEnum>)  y obtener el tipo de la enumeración de su parámetro genérico. 
  • Por último, usamos DropDownListFor() para generar el desplegable. En caso de tratarse de una propiedad obligatoria, añadimos un primer elemento con el texto “Select…”, y en caso contrario usamos el texto “(None)” para identificar el elemento nulo.

Y con esto ya tenemos hecho la mayor parte del trabajo, aunque aún nos falta un detalle. Por alguna razón que no llego a entender, ASP.NET MVC utiliza la plantilla string.cshtml (o el editor por defecto para el tipo string)  para editar las propiedades de tipo enum, lo cual nos obliga a indicar en las propiedades la plantilla a utilizar (las dos fórmulas usadas a continuación son equivalentes):

1
2
3
4
5
6
7
8
public class Contact
{
    public string Name { get; set; } 
    [UIHint("Enum")]
    public Language MainLanguage { get; set; }
    [DataType("Enum")]
    public Color? FavouriteColor { get; set; }
}

imageYa en ejecución, observamos que el resultado ha mejorado notablemente, como se puede apreciar en la captura de pantalla 🙂

En este punto podríamos considerar que hemos alcanzado el objetivo que nos proponíamos, pero… ¿no os parece aún demasiado trabajo tener que decorar cada propiedad de tipo enumeración con estos atributos? ¿No podríamos dejar al framework que se encargue de estas minucias?

3. Proporcionando metadatos con metadata providers

Ya hemos hablado por aquí en varias ocasiones de los proveedores de metadatos, o metadata providers. De hecho, si no tienes claro lo que son, te recomendaría que leyeras el post “Mamá, ¿de dónde vienen los metadatos” que publiqué haces unos meses.

Muy resumidamente, se trata del mecanismo que obtiene los metadatos de las clases del Modelo desde donde se encuentren definidos. El proveedor por defecto los obtiene examinando las clases y sus propiedades mediante reflexión y obteniendo los atributos (anotaciones) que definen restricciones y otras características, pero podemos crear proveedores personalizados que las extraigan desde otras fuentes.

Y vamos a utilizar esta característica para evitar tener que especificar el atributo [UIHint] a las propiedades de tipo enum. El proveedor cuyo código veremos a continuación hereda del usado por defecto en ASP.NET MVC 4 (CachedDataAnnotationsModelMetadataProvider) y sobrescribe el procedimiento de obtención de metadatos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class EnumMetadataProvider: CachedDataAnnotationsModelMetadataProvider
{
    protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(
        CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
    {
        var metadata = base.CreateMetadataFromPrototype(prototype, modelAccessor);
        var type = metadata.ModelType;
        if (type.IsEnum ||
            (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
            type.GetGenericArguments().Length == 1 && type.GetGenericArguments()[0].IsEnum))
        {
            metadata.TemplateHint = "Enum";
        }
        return metadata;
    }
}

Observad que lo único que estamos haciendo es invocar el método de la clase base y, posteriormente, comprobar si el tipo de la propiedad es un enumerado o un tipo anulable de enumerado, en cuyo caso introduce en la propiedad de metadatos TemplateHint el nombre de la plantilla a utilizar (“Enum”).

Por último, ya sólo queda establecer un objeto de este tipo como proveedor de metadatos por defecto para la aplicación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        // ...
 
        ModelMetadataProviders.Current = new EnumMetadataProvider();
    }
}

De esta forma, por fin podemos eliminar de nuestra clase del Modelo los molestos atributos y todas las enumeraciones de nuestra aplicación se mostrarán en el formulario con la plantilla de edición que hemos creado anteriormente 🙂

Publicado en: Variable Not Found.

Rutas en minúsculas en MVC 4 y ASP.NET 4.5

Seguro que alguna vez habéis notado que al generar URLs hacia acciones de una aplicación MVC usando helpers como Url.Action() o Html.ActionLink(), éstas son generadas usando mayúsculas y minúsculas según hubiéramos indicado en los parámetros de las llamadas:

Helper URL generada
@Url.Action("index", "home") /home/index
@Url.Action("List","Products", new{ Category="PC" }) /Products/List?Category=PC
@Url.Action("VIEWALL", "PRODUCTS") /PRODUCTS/VIEWALL

Como podemos ver, la URL resultante queda a criterio del desarrollador o, lo que es peor, al puro azar. A veces incluso no es algo que podamos elegir fácilmente, puesto que son generadas por otros componentes como T4MVC. Y no sé si desde el punto de vista del SEO tendrá su impacto, pero desde luego el ofrecer estas direcciones sin un aspecto unificado no da buena impresión.

En versiones anteriores a ASP.NET 4.5, esto podíamos solucionarlo creando helpers, o rutas personalizadas que, heredando de Route, realizaran esta conversión a minúsculas. Sin embargo, ahora disponemos de un mecanismo más cómodo para forzar que las URLs generadas sean normalizadas a minúsculas, así:

1
2
3
4
5
6
7
8
9
10
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.LowercaseUrls = true;
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        [...]
    }
}

Un detalle, sin duda interesante, para tener en cuenta en nuestros desarrollos.

Publicado en: Variable not found.

Asincronía en MVC 4

ASP.NET MVCEste es el mensaje que deberíamos interiorizar, si no lo hemos hecho ya, a la vista de las múltiples novedades introducidas en las últimas versiones de la plataforma ASP.NET y MVC:

Asíncronía = bueno

A grandes rasgos, la explicación es la siguiente: IIS tiene disponible un número limitado de hilos (threads) destinados a procesar las peticiones. Cuando llega una petición, uno de estos hilos es asignado en exclusiva a ella y permanecerá ocupado hasta que haya sido totalmente procesada. Si llegan peticiones cuando todos los hilos están ocupados, se introducen en una cola, también limitada. Cuando el tamaño máximo de esta cola ha sido superado, ya al servidor no le queda más remedio que responder con un error HTTP 503 al usuario indicándole que está seriamente ocupado.

Si las peticiones son “despachadas” de forma rápida es realmente difícil alcanzar estos límites. El problema aparece cuando el proceso de las peticiones requieren la ejecución de alguna tarea de larga duración que dependa de recursos externos, como puede ser una consulta pesada a la base de datos o la obtención de información desde un servicio web; en estos casos, el hilo asignado a la petición quedará bloqueado hasta que la tarea finalice.

Imaginemos, por ejemplo, el siguiente controlador:

1
2
3
4
5
public ActionResult ShowTheAnswer()
{
 var result = _oracle.GetTheAnswerToLifeTheUniverseAndEverything();
 return View(result);
}

Si la llamada a GetTheAnswerToLifeTheUniverseAndEverything() tardase, digamos 10 segundos, obviamente el usuario no vería el resultado hasta ese momento, pero, además, estaríamos desperdiciando un valioso recurso: el hilo asignado por IIS, que permanecería todo ese tiempo esperando a que el método realizara su trabajo. Probablemente, durante estos 10 segundos el mismo hilo podría haber atendido muchas otras peticiones.

Y es ahí donde se encuentra la gracia de los controladores asíncronos. Permiten “liberar” el hilo del servidor web para que pueda procesar otras peticiones mientras se espera el resultado de la ejecución de la tarea conflictiva. Una vez ésta ha finalizado, el servidor asignará otro hilo para que procese el resultado obtenido y finalmente retorne el resultado al cliente.

Al igual que antes, el usuario seguirá sin ver nada en su pantalla hasta transcurridos los 10 segundos, la diferencia está en que el servidor estará aprovechando mucho más los threads disponibles y, por tanto, será capaz de gestionar muchas más peticiones. Aunque en aplicaciones con poca carga normalmente no necesitaremos utilizarlos, sí suponen una diferencia importante cuando estamos hablando de dar servicio a una gran cantidad de usuarios concurrentes.

Acciones asíncronas en MVC 4

Los controladores asíncronos están disponibles desde las primeras versiones de ASP.NET MVC y, aunque permitían aplicar esta técnica, resultaban bastante tediosos de utilizar, pues parte de la gestión de la asincronía debíamos implementarla de forma manual. Podéis ver ejemplos aquí (Gisela Torres) o  aquí (Maxi Lovera).

A partir de MVC 4, y gracias a que la asincronía está siendo incorporada de forma masiva en el framework, podemos hacerlo de forma muchísimo más sencilla. Básicamente sólo tenemos que seguir cuatro pasos si usamos Visual Studio 2012 y ASP.NET 4.5:

  • Hacer que la acción retorne un Task<T>, donde T será normalmente del tipo ActionResult o alguno de sus descendientes.
  • Introducir en la declaración del método de acción la palabra clave async de C#, indicando de esta forma que se va a invocar un proceso asíncrono cuyo resultado obtendremos con await. Si no has oído hablar antes de estas dos novedades de la versión 5 de nuestro lenguaje favorito, puedes leer este post del gran Eduard Tomás donde las explica perfectamente.
  • Opcionalmente, si queremos seguir las convenciones de nombrado para métodos asíncronos, debemos añadir a su nombre el sufijo “Async”.
  • Por último, ya en el cuerpo de la acción, llamar a los métodos asíncronos usando await.

Nota: para conseguir lo mismo con Visual Studio 2010 es necesario instalar el Visual Studio Async CTP, aunque por lo que he podido comprobar no es una tarea sencilla.

Vamos a ilustrarlo con un ejemplo. El siguiente código muestra la versión síncrona, o tradicional, de un controlador, así como un método del Modelo que realiza un trabajo de larga duración:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Controller
public class OracleController : Controller
{
    [...]
    public ActionResult ShowTheAnswer()
    {
        var result = _oracle.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
        return Content("Response: " + result);
    }
}
 
// Model
public class Oracle
{
    [...]
    public int GetTheAnswerToLifeTheUniverseAndEverything()
    {
        Thread.Sleep(10000); // Simulate a very hard task
        return 42;
    }
}

Y a continuación mostramos la versión asíncrona de la misma acción y el correspondiente método del Modelo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Controller
public class OracleController : Controller
{
    [...]
    public async Task<ActionResult> ShowTheAnswerAsync()
    {
        var result = await _oracle.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
        return Content("Response: " + result);
    }
}
 
// Model
public class Oracle
{
    [...]
    public Task<int> GetTheAnswerToLifeTheUniverseAndEverythingAsync()
    {
        return Task.Factory.StartNew(() =>
        {
            Thread.Sleep(10000); // Simulate a very hard task
            return 42;
        });
    }
}

Desde el punto de vista del Controlador, la llamada al método del Modelo retornará un objeto de tipo Task que representará a la tarea que ha comenzado a realizarse en segundo plano. El uso de await hará que el thread del servidor web sea liberado, y que se vuelva a tomar el control en este punto cuando la tarea haya finalizado y ya tengamos un resultado disponible.

Por tanto, podríamos generalizar el patrón para la implementación de acciones asíncronas que retornan una vista de la siguiente forma:

1
2
3
4
5
public async Task<ActionResult> MyAction(param1, param2…)
    {
        var result = await AsyncOperation();
        return View(result);
    }

¿Más de una tarea asíncrona desde el interior de la acción?

Si estamos ante un escenario en el que necesitamos ejecutar más de una tarea asíncrona en la misma acción, podemos optar por hacerlo de forma secuencial o paralelizar también estas tareas.

El primer enfoque, bastante trivial, consistiría en realizar las llamadas una detrás de otra. Por ejemplo, volviendo sobre el ejemplo anterior, si quisiéramos obtener una segunda opinión sobre las verdades del universo, podríamos hacer como sigue:

1
2
3
4
5
6
public async Task<ActionResult> ShowTheAnswerAsync()
{
    var result1 = await _oracle1.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
    var result2 = await _oracle2.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
    return Content("Response: " + (result1+result2)/2);
}

La primera llamada al método asíncrono retornará el Task<int> representando a la tarea que acabará de comenzar a ejecutarse, y la palabra clave await hará que el hilo quede liberado hasta que se obtenga la primera respuesta, momento en que se volverá a tomar el control para introducirla en result1. A continuación se hará lo mismo para obtener la segunda opinión.

El tiempo total de ejecución, desde que la acción comienza a ejecutarse hasta que el resultado es enviado al cliente será de 20 segundos, asumiendo que cada llamada tarda 10 segundos.

La otra posibilidad es paralelizar ambas llamadas. En este caso, lanzamos las dos tareas en paralelo, obteniendo las referencias hacia las mismas, y usamos awaitWhenAll()  para esperar la finalización de ambas:

1
2
3
4
5
6
7
public async Task<ActionResult> ShowTheAnswerAsync()
{
    var task1 =  _oracle1.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
    var task2 =  _oracle2.GetTheAnswerToLifeTheUniverseAndEverythingAsync();
    await Task.WhenAll(task1, task2);
    return Content("Response: " + (task1.Result+task2.Result)/2);
}

En este caso, dado que ambas tareas se realizan de forma simultánea, el resultado será mostrado al usuario en 10 segundos.

That’s all, folks!

Bueno, hay más cosas que contar, pero de momento vamos a dejarlo aquí 🙂

La implementación de acciones asíncronas para la realización de tareas de cierta duración aporta grandes beneficios en sistemas de alta concurrencia, y con ASP.NET MVC 4 resulta realmente sencillo.

Su uso está recomendado cuando la acción vaya a realizar una tarea de larga duración e involucre el acceso a recursos externos. Es decir, si el proceso a realizar es costoso pero de uso intensivo de CPU, no se obtendrá un beneficio destacable.

Más información en: Using Asynchronous Methods in ASP.NET MVC 4

Publicado en: Variable not found.

TypeScript: un primer vistazo

TypeScriptSiempre he tenido la sensación de que Javascript no ha evolucionado de forma proporcional a las responsabilidades y expectativas que han ido depositando en él. El explosivo crecimiento que ha sufrido en los últimos años no venía acompañado de mejoras en el lenguaje que nos ayudaran a implementar aplicaciones cada vez más extensas y complejas, para las que es muy conveniente disponer de herramientas más potentes que las ofrecidas de serie por este veterano lenguaje.

Y Microsoft ha movido ficha. Hace un par de días, S. Somasesegar, vicepresidente corporativo de la división de desarrollo de la casa, presentó un nuevo lenguaje que pretende acabar con las tradicionales carencias de Javascript, al que han denominado TypeScript. Detrás de este nuevo “invento” está el mismísimo Anders Hejlberg, padre de C# y otras maravillas, que ya sabíamos hace tiempo que andaba liado con algo relacionado con Javascript.
image
En cuanto a sintaxis, TypeScript es un superconjunto de Javascript, es decir, todo código Javascript es código TypeScript. Sin embargo, amplía al original para dotarlo de características como clases, interfaces, módulos, importación de archivos, visibilidades públicas y privadas, o incluso strong typing mediante el uso de anotaciones o nuevas palabras clave, todas ellas de uso opcional.

El resultado de compilar código TypeScript es Javascript estándar, lo que quiere decir que se podemos usarlo normalmente y la salida será directamente utilizable en cualquier navegador sin necesidad de instalar plugins o máquinas virtuales específicas para soportar esta tecnología, al igual que podrá correr sobre Node.js o cualquier intérprete o compilador del estilo.

Como ya empieza a parecer normal en Microsoft, este proyecto es Open Source (licencia Apache 2.0) y es posible acceder al código fuente desde Codeplex. La versión actual es la 0.8.

Por cierto, el motivo de entrecomillar “invento” algunos párrafos más arriba es que conceptualmente no se trata de algo nuevo. Hace tiempo que existen lenguajes que pueden ser compilados a Javascript, como CoffeScript, Dart, Kaffeine, y muchos más, aunque normalmente usan una sintaxis propia más o menos alejadas de sus orígenes, por lo que su adopción es más costosa.

También existen compiladores cruzados como Saltarelle, recientemente presentado, que permiten escribir código C# y generar Javascript, aunque obviamente en este caso estaríamos alejándonos de la realidad que hay por detrás.

Instalación de TypeScript

En primer lugar, he de decir que para una primera toma de contacto con el  lenguaje no es necesario descargar ni instalar nada. La web oficial de TypeScript incluye un completo playground donde podemos escribir directamente en este lenguaje, obteniendo el resultado en Javascript en tiempo real. Muy recomendable echarle un vistazo 🙂
Instalando TypeScript
Pero si preferimos comenzar a usarlo, en la misma web se describe cómo descargarlo en Node.js (distribuido como paquete NPM) y en Visual Studio 2012 (incluida la versión  Express). En este último caso, debemos descargar e instalar el plugin, con el que conseguiremos una integración bastante razonable del lenguaje en el entorno, y casi estaremos listos para entrar en faena.

Una vez instalado, ya podremos crear y editar archivos TypeScript, que tienen extensión .ts, aunque aún tendremos que hacer algún apaño para que éstos sean compilados de forma automática. También podemos compilar a través de línea de comandos, pero obviamente no es la manera más cómoda de hacerlo 😉

Bueno, una posibilidad rápida para probarlo es crear un proyecto MVC 3 (¡sí, MVC 3!), y veremos que aparece una nueva plantilla llamada “TypeScript Internet Application”:

Nueva plantilla de proyecto
En este caso, ya en la carpeta /Script podremos ver algunos archivos .ts y comenzar a curiosear o desarrollar nuestros propios componentes usando este lenguaje.

Pero ojo, que los archivos .ts sólo son compilados cuando se compila el proyecto; es decir, el correspondiente .js no se generará automáticamente al salvar el archivo TypeScript, aunque supongo que esto cambiará en el futuro. En cualquier caso, el archivo .js, obviamente, es el que deberemos referenciar desde nuestras vistas o páginas.

Si preferimos usar otro tipo de proyecto como ASP.NET Web Forms o MVC 4, tendremos que añadir de forma manual el siguiente código en el archivo .csproj para que los ficheros .ts sean compilados junto con el proyecto:

1
2
3
<Target Name="BeforeBuild">
   <Exec Command="&amp;quot;$(PROGRAMFILES)Microsoft SDKsTypeScript.8.0.0tsc&amp;quot; @(TypeScriptCompile ->'&quot;%(fullpath)&quot;', ' ')" />
</Target>

Esta porción de código debemos añadirla al final del archivo .csproj del proyecto, sustituyendo (o complementando, si ya tenemos eventos de compilación) la sección <Target> del mismo.

Eso sí, asegurad que el bloque no está comentado porque entonces este cambio no será tenido en cuenta. Os cuento esto porque por defecto esta sección viene comentada y si incluimos en ella el código y no eliminamos los comentarios no os funcionará (a mí me ha llevado un rato darme cuenta ;-)).

Algunas características de TypeScript

La especificación de TypeScript ya está disponible, y su lectura puede dar una idea de las principales características del lenguaje. Vamos a ver algunas de ellas.

En TypeScript, podemos añadir información de tipo a las funciones, parámetros y variables, siempre opcionalmente:

Tipado

El editor integrado en Visual Studio en todo momento ofrecerá ayuda sobre los métodos disponibles, los tipos de datos, etc… ¡full intellisense power! Incluso en el mismo editor podremos ver los errores que cometemos en el código y harán fallar la compilación.

En un principio, disponemos de los tipos primitivos string, number, y bool, así como de otros tipos especiales como any (similar a object, la clase base para todos los tipos), void (similar a la sintaxis C#), Null, o Undefined. También existe inferencia de tipos al usar var:

Tipos

¿Y a quién no le gusta usar parámetros opcionales?

Parámetros opcionales

También podemos usar una sintaxis tipada para los tipos función, de forma bastante parecida a las habituales expresiones lambda:

Tipos función

Podemos escribir clases, con propiedades, constructor y métodos de forma muy sencilla y natural:

Clases

Y, por supuesto, es posible usar herencia y sobrescribir métodos:

Herencia

Las clases pueden tener miembros públicos y privados e intellisense será consciente de ello. Por defecto, como en Javascript, son públicos:

Visibilidad

¿Y usar interfaces? Pues también:

Interfaces

Es posible organizar el código en módulos que, por supuesto, pueden ser almacenados en archivos externos para hacer más manejables las aplicaciones de cierto volumen:

Módulos

Lógicamente hay muchos detalles más, pero creo que lo visto es suficiente para hacernos una idea del enfoque de TypeScript. Os remito a las especificaciones del lenguaje para ampliar información.

En todos los casos que hemos visto el código Javascript generado al compilar es limpísimo, muy legible, totalmente respetuoso con los estándares, y usa los patrones y buenas prácticas habituales de este lenguaje. Por ejemplo, el Javascript generado correspondiente al módulo anterior es el siguiente:

Javascript generado

Dado que la generación de los archivos .js se realiza en tiempo de compilación, estos ficheros pueden ser incluidos en el proceso habitual de publicación en los servidores de producción, podemos seguir usando los bundles o sistemas de compactación y minimización, etc.

Finalmente, decir que la primera impresión es bastante positiva. Si el concepto ya era atractivo, la potencia y sencillez del lenguaje propuesto por Microsoft y su integración con Visual Studio harán de este producto una interesantísima opción para solventar fácilmente algunas de las trabas que encontramos al trabajar con Javascript puro, a cambio de un esfuerzo de aprendizaje mínimo y usando un procedimiento muy poco intrusivo en nuestros desarrollos. Habrá que estar atentos a la evolución del producto.

Eso sí, todavía quedan algunos detalles por pulir, como la mejor integración con el entorno (por ejemplo, generar Javascript al grabar el archivo en lugar de esperar a compilar), pero seguramente estarán solucionados para la versión definitiva.

Enlaces:

Publicado en: Variable not found.

ASP.NET MVC 4: DisplayModes organizados por carpetas

 

ASP.NET MVCHace poco hablábamos de la creación de Display Modes personalizados en ASP.NET MVC 4, y veíamos cómo hacerlo usando la clase DefaultDisplayMode proporcionada por el framework, con la que podíamos cubrir la mayoría de necesidades comunes.

Así, veíamos cómo el siguiente código era suficiente para registrar un nuevo Display Mode llamado “iPhone”, que sería activado cuando en el identificador del agente de usuario (encabezado user-agent de la petición) incluyera el texto “iPhone”:

DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
{
    ContextCondition = (context => context.Request.UserAgent.IndexOf
        ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
});
 

imageHecho esto, ya podíamos definir vistas alternativas a las habituales específicas para este dispositivo, cuyos nombres de archivo acabarían siempre en “.iphone.cshtml”. Observad que estamos usando la clase DefaultDisplayMode, a la que estamos facilitando la condición que debe cumplirse para que se active este Display mode.

Sin embargo, si pensamos crear muchas vistas específicas para dispositivos, podríamos encontrarnos con un maremagnum de archivos como el que veis en la captura de pantalla adjunta.

Obviamente, no es una situación fácilmente manejable, así que ¿por qué no cambiar la forma de nombrar los archivos dependiendo del Display Mode actual? Pues dicho y hecho, vamos a conseguir que cada dispositivo disponga de una carpeta específica para guardar sus vistas.

Heredando de DefaultDisplayMode

Si analizamos el código fuente de la clase DefaultDisplayMode, veremos que hay varios miembros virtuales que podemos sobrescribir para tomar el control, y uno de ellos es el método TransformPath(), encargado de transformar la ruta hacia el archivo físico donde está definida la vista teniendo en cuenta el nombre del Display Mode actual.

El código por defecto del método es el siguiente:

    protected virtual string TransformPath(string virtualPath, string suffix)
    {
      if (string.IsNullOrEmpty(suffix))
        return virtualPath;
      string extension = Path.GetExtension(virtualPath);
      return Path.ChangeExtension(virtualPath, suffix + extension);
    }

O sea, que se reemplaza la extensión del archivo, normalmente “.cshtml” por el resultado de concatenar el sufijo suministrado (el nombre del Display Mode) a dicha extensión. Por esta razón, el comportamiento por defecto del framework es utilizar construcciones como “nombrevista.iphone.cshtml”.

Si, como es el caso, queremos cambiar la ruta donde van a intentar localizarse las vistas, lo único que tenemos que hacer es crear una clase descendiente de DefaultDisplayMode, sobrescribir la forma de “montar” la ruta hacia la vista, y utilizar esta nueva clase para registrar los modos de visualización que nos interesen. Una posible implementación podría ser la siguiente:

    public class OrganizedDisplayMode: DefaultDisplayMode
    {
        public OrganizedDisplayMode(string displayModeId): base(displayModeId)
        {
        }
 
        protected override string TransformPath(string virtualPath, string suffix)
        {
            if (string.IsNullOrEmpty(suffix))
                return virtualPath;
 
            // Transforms /index.cshtml --> /suffix/index.cshtml
            int lastSeparator = virtualPath.LastIndexOf('/');
            virtualPath = virtualPath.Substring(0, lastSeparator) + 
                            "/" + suffix + 
                            virtualPath.Substring(lastSeparator);
            return virtualPath;
        }
    }

Vistas estructuradas por carpetasY en la inicialización de la aplicación ya podríamos registrar este Display Mode y asociarlo a la condición que esperamos que cumpla la petición:

  DisplayModeProvider.Instance.Modes.Insert(0,
     new OrganizedDisplayMode("iPhone") 
     {
        ContextCondition = 
           context => context.Request.UserAgent.Contains("iPhone")
     });

De esta forma, ya podemos organizar las vistas como podéis observar en la captura de pantalla de la derecha: cada dispositivo (o Display Mode registrado) dispondría de una carpeta en cuyo interior se encontrarían las vistas específicas para el mismo.

Y observad que su funcionamiento no se limita a las vistas asociadas a controladores concretos, la solución también sería válida en vistas compartidas (Shared) y con aquellas incluidas en áreas 🙂

Publicado en Variable not found.

ASP.NET MVC 4 y los nuevos atributos de validación de .NET 4.5

ASP.NET MVCUn post rapidito. Según puede consultarse en MSDN, ya tenemos confirmado que la versión 4.5 de .NET framework vendrá acompañada de un nuevo conjunto de atributos de validación para aplicar a las propiedades del Modelo en el espacio de nombres System.ComponentModel.DataAnnotations:

  • CreditCardAttribute, que puede ser utilizado para validar números de tarjeta de crédito.
  • EmailAddressAttribute, que validará direcciones de correo electrónico.
  • FileExtensionsAttribute, para validar extensiones en nombres de archivo.
  • PhoneAttribute, que indica cuándo una propiedad debe contener un número de teléfono válido.
  • UrlAttribute, que comprobará si el contenido de una propiedad es una URL válida.
  • CompareAttribute, que antes estaba disponible en System.Web.Mvc y ha “ascendido” a anotación de datos general, permite validar la igualdad de dos propiedades.

Pues bien, según se observa en este changeset del código fuente del framework, ya podemos asegurar que la versión final de MVC 4 incorporará adaptadores de cliente y servidor para que podamos utilizarlos de forma directa en nuestros desarrollos 🙂

También se ha incluido soporte para el atributo MembershipPasswordAttribute, recientemente incluido en System.Web.Security, que comprueba si una contraseña cumple los requisitos establecidos para las mismas en el membership provider.

Publicado en Variable not found.

DisplayModes en MVC 4

Como venimos comentando desde la aparición de la preview de MVC 4, el Display Mode o modo de visualización es un nuevo mecanismo que permite la creación de aplicaciones capaces de retornar vistas específicas según las características y capacidades del cliente conectado u otros parámetros del entorno de la petición.

Esto tiene mucha utilidad directa, por ejemplo, a la hora de construir aplicaciones web que adapten su interfaz en función de si el cliente es un dispositivo móvil o desktop, pero como casi siembre ocurre en el framework, se trata de un mecanismo muy extensible y fácil de adaptar a otras necesidades.

¿Cómo funciona?

Las aplicaciones, tanto ASP.NET MVC 4 como WebPages 2, disponen de una lista de display modes admitidos, a la que se puede acceder a través de la propiedad DisplayModeProvider.Instance.Modes. Esta colección está poblada inicialmente por dos elementos, aunque podemos añadir todos los que nos interesen siempre que éstos implementen el interfaz IDisplayMode, cuya definición es la siguiente:

public interface IDisplayMode
{
    string DisplayModeId { get; } 
    bool CanHandleContext(HttpContextBase httpContext);

    DisplayInfo GetDisplayInfo(HttpContextBase httpContext, 
                               string virtualPath,
                               Func<string, bool> virtualPathExists);
}

Cuando llega una petición, el mismo sistema de routing recorrerá la colección DisplayModeProvider.Instance.Modes, e invocará el método CanHandleContext() de cada uno de los objetos IDisplayMode encontrados en ella. El primero que responda afirmativamente será introducido en el contexto de la petición como modo de visualización activo.

A partir de ese momento es posible consultar el display mode actual a través de la propiedad DisplayMode disponible en la clase ControllerContext .

Continuando con el ciclo de vida de la petición, una vez ésta ha sido procesada por el controlador, si éste retorna una vista entrarán en juego los motores de vistas o view engines. Éstos son los encargados, entre otras cosas, de localizar el archivo de plantilla (.cshtml, aspx, etc.) a usar para renderizar la vista en función del nombre de ésta, del nombre del controlador, y, si procede, del área activa. Por ejemplo, si es necesario retornar una vista llamada “index”, del controlador “customers”, en el área “admin”, el motor de vistas Razor (implementado en la clase RazorViewEngine) será capaz de localizar y crear la vista a partir de la plantilla disponible en /areas/admin/views/customers/index.cshtml.

Pues bien, el modo de visualización activo toma relevancia justo en el momento de la localización de la plantilla. El view engine encargado de procesar la vista llamará al método GetDisplayInfo() de éste, desde donde tendrá la oportunidad de modificar la ruta hacia el archivo. En la implementación por defecto, el identificador del display mode activo, tomado de su propiedad DisplayModeId, será insertado como prefijo de la extensión del archivo, de forma, por ejemplo, que la vista que tradicionalmente hubiéramos encontrado en “~/views/home/index.cshtml”, usando el modo de visualización identificado como “mobile” se encontraría en “~/views/home/index.mobile.cshtml”.

Display Modes por defecto

Antes había comentado que al arrancar una aplicación MVC 4 o WebPages 2, la colección de modos de visualización, DisplayModeProvider.Instance.Modes, es cargada con dos elementos. Ambos son del tipo DefaultDisplayMode, clase que, por supuesto, implementa IDisplayMode, e implementa unas bases bastante genéricas y reutilizables.

El primer display mode que encontramos es el específico para dispositivos móviles, que nivel a de framework se define más o menos así:

var displayMode = new DefaultDisplayMode(DisplayModeProvider.MobileDisplayModeId)
                        {
                            ContextCondition =
                                context => context.GetOverriddenBrowser().IsMobileDevice
                        };

El parámetro que estamos enviando al constructor es el identificador que daremos al modo de visualización (y, por tanto, que será usado como prefijo de la extensión del archivo de la vista). La constante DisplayModeProvider.MobileDisplayModeId está definida con un valor de “Mobile” en el código, y por esta razón las vistas específicas para móviles las encontraremos en archivos del tipo “xyz.mobile.cshtml”.

Por otra parte, haciendo uso de la inicialización rápida de objetos de C#, establecemos en la propiedad ContextCondition la condición que activará el display mode, expresado como lambda. La expresión lambda recibe un parámetro de tipo HttpContextBase y debe retornar un booleano, que será el valor que retorne el método CanHandleContext(), como recordaréis, invocado por el framework para averiguar si un IDisplayMode puede procesar una petición.

Por cierto, el GetOverridenBrowser() que veis ahí es otra característica nueva que encontraremos en MVC 4; de momento, quedaos con que, simplemente, nos devuelte información sobre el cliente que ha realizado la petición. Le dedicaremos un post en exclusiva más adelante 😉

El segundo display mode que encontramos en DisplayModeProvider.Instance.Modes es una instancia de la clase DefaultDisplayMode a la que no se ha establecido ninguna propiedad; las llamadas a su método CanHandleContext() siempre retornan true, y su identificador es una cadena vacía.

Teniendo este objeto al final de la lista al más puro estilo catch-all, conseguimos que si ninguno de los display modes es capaz de gestionar adecuadamente la petición, se procesará éste, y dado que su identificador es una cadena de texto en blanco, no se producirá ningún cambio en el nombre del archivo. En otras palabras, el framework seguirá funcionando como hasta ahora, por lo que este elemento es, al fin y al cabo, el que garantiza la compatibilidad hacia atrás de este mecanismo.

Creación de display modes personalizados

Como ya podréis intuir, es bastante sencillo crear nuevos display modes, cuya activación dependa de las condiciones que más nos interesen. Lo más sencillo es utilizar como base el DefaultDisplayMode, por ejemplo así:

DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
{
    ContextCondition = (context => context.Request.UserAgent.IndexOf
        ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
});

Con el código anterior estaríamos creando un nuevo display mode que se activaría cuando en el user-agent de la petición (enviado en el encabezado HTTP) se encuentre el texto “iPhone”, lo que permitiría crear vistas específicas para este dispositivo nombrándolas de la forma “xyz.iphone.cshtml”.

Otra posibilidad sería crear una clase que implemente IDisplayMode e introducir en ella la lógica que deseemos ejecutar en cada uno de los miembros definidos en el contrato. Pero el ejemplo y el escenario en el que podría ser utilizado lo dejamos para un futuro post 😉

Publicado en: Variable not found.