Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

19 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
miércoles, 15 de septiembre de 2010
ASP.NET MVC, por su natural integración con Ajax, es un candidato perfecto para implementar software al “estilo 2.0”, consiguiendo efectos sorprendentes y nuevas formas de interacción con el usuario desde la web similares a las que nos ofrecen aplicaciones como GMail o Blogger.

En este post vamos a ver cómo implementar un formulario con auto-salvado, es decir, capaz de ir enviado su contenido al servidor periódicamente con objeto de evitar la pérdida de toda la información si el usuario sale de forma involuntaria de la aplicación o se pierde la conexión.

Y todo ello de forma no intrusiva, sin afectar a las funcionalidades habituales en casos en que el usuario haya deshabilitado los scripts en el navegador… ¿qué más podemos pedir? ;-)

1. Objetivo

Vamos a empezar por el final, para que quede claro a dónde pretendemos llegar. Implementaremos un mantenimiento para la gestión simple de posts de un motor de blogs, para lo que nos basaremos en las vistas y controladores generados automáticamente por Visual Studio.

La siguiente captura muestra el interfaz principal del mantenimiento; seguro que apreciáis la originalidad del diseño ;-)

Pantalla principal del mantenimientoAl editar o crear un post accederemos a la pantalla de edición, en la que pretendemos crear la funcionalidad de autoguardado, que se puede ver en ejecución en la siguiente captura:

Autoguardado en funcionamiento
Mientras el usuario esté introduciendo los datos solicitados por el formulario, el sistema de auto-guardado irá activándose cada X segundos, enviando al servidor los datos presentes en los campos del formulario en ese momento. Eso sí, el usuario en ningún momento será interrumpido, puesto que este envío se realizará en segundo plano, mediante una discreta llamada Ajax.

Así, si se produce algún problema como el cierre involuntario del navegador, la salida de la aplicación, o simplemente al usuario se le corta el suministro eléctrico, se podrá recuperar la información enviada en el último salvado automático.

2. La solución, a vista de pájaro

La implementación del autoguardado atenderá estructuralmente al patrón MVC, por lo que:
  • implementaremos en el Modelo la lógica de recuperación y actualización de datos. Utilizaremos una clase de servicio en la que expondremos los métodos de manipulación de información que vamos a permitir; para el acceso a datos utilizaremos Entity Framework.
  • el controlador dispondrá de una acción específica para salvar los datos enviados desde la vista.
  • la vista incluirá los scripts que realizan la invocación periódica de la acción del controlador vía Ajax, suministrándole la información disponible en el formulario.
Al final del post encontrarás un enlace para descargar la solución completa. En ella podrás ver otras técnicas, que no comento por aquí para no alargar demasiado este texto, como la eliminación de posts usando también Ajax no intrusivo, o el uso de plantillas y templated helpers para la reutilización del interfaz de edición.

3. El Modelo

Modelo conceptualNuestro modelo es bastante simple, puesto que estamos centrándonos exclusivamente en las funcionalidades que necesitamos para implementar el ejemplo de autoguardado.

El diagrama del modelo conceptual de Entity Framework es el que se muestra adjunto. Una única entidad, Post, con escasas propiedades para no distraernos mucho de nuestro objetivo final.

Hemos creado también la correspondiente clase de metadatos con la que aportaremos información necesaria para la validación de la información:

[MetadataType(typeof(PostMetadata))]
public partial class Post
{
}
 
public class PostMetadata
{
    [DisplayName("Título")]
    [Required]
    public string Titulo { get; set; }
 
    [DisplayName("Texto")]
    public string Texto { get; set; }
}

La clase de servicio que implementa las funcionalidades de alto nivel del modelo se denomina BlogServices, con la siguiente estructura:

public class BlogServices: IDisposable
{
    public IEnumerable<Post> GetPosts() { }
    public Post GetPostById(int id) { }
    public void Save(Post post) { }
    public bool DeletePost(int id)  {  }
    public void Dispose() {}
}

El método Save() es el único que merece la pena destacar. Su objetivo es comprobar si existe el post, para lo cual nos basamos en la propiedad IdPost: si vale cero, asumiremos que el post es de nueva creación, por lo que lo insertaremos en la base de datos; en caso contrario, adjuntaremos la entidad al contexto y la marcamos como modificada para que sea actualizada al confirmar los cambios:

public void Save(Post post)
{
    post.Fecha = DateTime.Now;
    if (post.PostId == 0)
    {
        post.Fecha = DateTime.Now;
        _data.AddToPosts(post);
    }
    else
    {
        _data.Posts.Attach(post);
        _data.ObjectStateManager.ChangeObjectState(post, EntityState.Modified); 
    }
    _data.SaveChanges();
}

Por simplificar el ejemplo, no se han tenido en cuenta los posibles errores de concurrencia.

4. El Controlador

El controlador que podréis encontrar en el código fuente del proyecto incluye las acciones habituales para crear, actualizar, eliminar y obtener la relación de posts almacenados en el sistema.

public class PostsController : Controller
{
    private BlogServices services = new BlogServices();
 
    [HttpGet]  public ActionResult Index() { ... }
    [HttpGet]  public ActionResult Edit(int id) { ... }
    [HttpPost] public ActionResult Edit(Post post) { ... }
    [HttpGet]  public ActionResult Create() { ... }
    [HttpPost] public ActionResult Create(Post post) { ... }
    [HttpGet]  public ActionResult Delete(int id) { ... }
 
    [HttpPost] public JsonResult SavePostAjax(Post post) { ... }
}

El último método de acción, SavePostAjax(), es el que recibirá los datos desde la vista, y su implementación es la mostrada a continuación:

[HttpPost]
public JsonResult SavePostAjax(Post post)
{
    if (this.ModelState.IsValid)
    {
        services.Save(post);
        Thread.Sleep(2000);   // Un retardo
        return Json(new
                    {
                        grabado = true,
                        Id = post.PostId
                    }
        );
    }
    else
    {
        return Json(new
        {
            grabado = false
        });
    }
}

Como se puede observar, tras comprobar la validez de los datos recibidos, invocamos al método Save() del objeto services, una instancia de la clase BlogService descrita en el Modelo y cuya implementación hemos visto anteriormente, que grabará los datos en el almacén.

El método retorna un objeto anónimo serializado en JSON, que presenta como máximo dos propiedades: grabado, que indicará si el Post ha sido almacenado con éxito, e Id, que retornará el identificador asignado al Post cuando haya sido salvado por primera vez.

La llamada a Thread.Sleep() hace que la ejecución quede en pausa un par de segundos, para que cuando estamos en local al menos nos de tiempo a ver los mensajes en pantalla. Obviamente, este código no debería aparecer en producción.

5. La Vista

En la vista es donde se encuentra la mayor parte de la magia del autosalvado. Obviamente, estas funcionalidades estarán basadas en scripts, por lo que nos apoyaremos bastante en la inigualable jQuery.

El formulario de edición es totalmente normal, como podría una vista tipada de edición generada por Visual Studio, lo que asegurará la compatibilidad con clientes sin scripts. Será idéntico para el interfaz de edición y de creación:

Código del formulario de edición
Fijaos que estamos dejando un campo oculto para almacenar el PostId del Post que estamos editando. Cuando estemos creando un post, éste campo almacenará el valor cero, pero una vez el proceso automático envíe por primera vez sus datos, introduciremos en su interior el ID asignado desde la base de datos; así, el siguiente autosalvado, ya no realizará una inserción sobre la base de datos, sino una actualización :-)

El siguiente código script muestra la forma en que activamos el guardado automático sobre el formulario de edición:

<script type="text/javascript">
    $(function () {
        backgroundSaver('<%= Url.Action("SavePostAjax")%>', 15000, getData, setId);
    });
 
    function getData() {
        if ($.trim($("#Texto").val()) == "")
            return null;
        else
            return {
                PostId: $("#PostId").val(),
                Titulo: $("#Titulo").val() || "No definido",
                Texto: $("#Texto").val()
            };
    }
 
    function setId(id) {
        $("#PostId").val(id);
    }
 
</script>


Al terminar la carga de la página invocamos a la función backgroundSaver(), cuyo código veremos más adelante, pasándole los siguientes parámetros:
  • en primer lugar, el nombre de la acción que recibirá los datos, obtenida con el helper Url.Action(),
  • a continuación el número de milisegundos entre guardado y guardado de datos; en el ejemplo anterior, los datos serán enviados cada 15 segundos,
  • seguidamente, la función que utilizará backgroundSaver() para obtener los datos a enviar al servidor, getData(),
  • y por último, la función mediante la cual backgroundSaver() nos informará del identificador asignado al post cuando éste haya sido guardado por primera vez, setId().
La función getData() debe retornar un objeto anónimo con los datos que queremos enviar al servidor. En nuestro caso, dado que se trata de una instancia de Post, definimos en el objeto anónimo las propiedades PostId, Titulo y Texto, cuyos valores tomamos de los campos del formulario. En el título, además, introducimos un valor por defecto para cuando éste no haya sido definido aún.

Observad que hemos introducido una condición previa: si el usuario no ha introducido nada aún en el campo Texto, retornamos un nulo, lo que provocará que backgroundSaver() no efectúe la llamada Ajax al servidor.

Sería muy sencillo introducir aquí otras condiciones para impedir peticiones Ajax en momentos en los que no tenga sentido. Por ejemplo, podríamos crear un flag global que indicara si el valor de los campos han cambiado (utilizando los eventos de cambio o pulsación de teclas de los controles), y sólo permitir la llamada cuando dicho indicador fuera cierto.

La función setId() será invocada por el proceso de autoguardado cuando haya conseguido almacenar los datos, enviándonos como argumento el identificador asignado al Post por la base de datos.

Lo único que hacemos con ese valor es almacenarlo en el campo oculto que habíamos dispuesto para este propósito. Ya la siguiente vez que guardemos el Post, bien sea de forma manual pulsando sobre el botón "Almacenar" del formulario, o bien de forma automática mediante el autosalvado, la información será actualizada en la base de datos y no se insertará un nuevo registro.

La función backgroundSaver() también es bastante simple. Internamente define dos métodos:
  • prepareNext(), que programa el siguiente autosalvado,
  • saveForm(), que es la que lanza la petición Ajax al servidor.
Ahí va su código:

var backgroundSaver = function (action, timer, getData, setId) {
    var saveForm = function () {
        var data = getData();
        if (data == null) {             // Cancelamos el envío
            prepareNext();          
            return;
        }
        $("#autosaving").show();
        $.ajax({
            url: action,
            type: 'post',
            cache: false,
            data: data,
            success: function (retorno) {
                $("#autosaving").hide();
                if (retorno.grabado) {
                    if (typeof (setId) == 'function') {
                        setId(retorno.Id);
                    }
                }
 
                prepareNext();
            },
            error: function (d) {
                $("#autosaving").hide();
                prepareNext();
            }
        });
    }
 
    var prepareNext = function () {
        setTimeout(saveForm, timer);
    };
 
    prepareNext();
}


El cuerpo de la función saveForm() contiene la llamada Ajax al servidor. Tras comprobar que la llamada a la función callback getData() no ha retornado un nulo, se realiza la llamada utilizando el método ajax() de jQuery. Si la petición se completa con éxito, se invoca a setId() para notificar al código cliente del ID asignado al Post.

Si en el formulario existe un elemento visual llamado #autosaving, la función anterior se encargará de mostrarlo y ocultarlo cuando corresponda, a modo de indicador de progreso. En nuestro caso, las vistas incluyen un marcado como el siguiente:

Indicador de progreso

6. ¡Y eso es todo!

A pesar de la extensión del este post, implementar esta característica es realmente sencillo, y aporta una espectacularidad impresionante a nuestros formularios, muy en la línea de las modernas aplicaciones 2.0, y por supuesto, grandes ventajas para los usuarios.

Obviamente la implementación descrita no es perfecta; podría ser mejorada en mucho añadiendo más automatismos, como la detección automática de cambios en el formulario, o el control de errores, pero no era ese el objetivo que pretendía, así que os lo dejo de deberes ;-)

Podéis descargar el proyecto de demostración, para VS2010 y SQL Express 2008.

Publicado en: Variable not found.
domingo, 12 de septiembre de 2010
Y tras el paréntesis vacacional, también volvemos con los posts que resumen los enlaces difundidos desde Variable not found en Facebook y Twitter durante los últimos días.

Van dedicados al amigo Sebastián H., que según me comenta por correo, le resultan muy interesantes. :-)
Y no olvides que puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.

Publicado en: Variable not found
martes, 7 de septiembre de 2010
ASP.NET MVC Una cuestión que consultan frecuentemente los alumnos del curso de MVC que tutorizo en CampusMVP, y que veo en los foros oficiales del framework trata sobre el uso correcto de rutas hacia recursos utilizados por las páginas, como scripts, estilos o imágenes.

Unas referencias erróneas hacia las páginas de estilo o imágenes pueden hacer que un sitio web, o parte de éste, deje de visualizarse correctamente; en el tema de scripts es más grave pues en el peor de los casos el sistema puede dejar de funcionar o presentar un comportamiento anómalo, sobre todo si se hace uso intensivo de bibliotecas como jQuery o MS Ajax.

Para mayor desgracia, muchas veces la aparición de estos síntomas es tardía. Todo parece funcionar correctamente en desarrollo, con el servidor integrado de Visual Studio, y falla estrepitosamente al publicarlo en el IIS de producción, lo cual puede provocar un cierto nerviosismo y la aparición de frases como "¡en mi máquina funciona!" ;-).

¿Y por qué es tan habitual encontrar problemas en esto, a priori tan sencillo? En mi opinión, por las prisas y la comodidad, sin duda malas compañías para los desarrolladores. Y conste que no seré yo quien tire la primera piedra...

Sin duda es realmente cómodo arrastrar un recurso (script, estilo…) desde el explorador de proyectos y dejarlo caer sobre una vista; Visual Studio es lo suficientemente inteligente como para generar la etiqueta apropiada para referenciarlo.

Por ejemplo, editando el archivo /Views/Home/Index.aspx, podemos arrastrar directamente el archivo /Content/Site.css y el entorno generará un tag <link> completo:

Arrastrar recurso sobre una vistaSin embargo, si nos fijamos bien, la ruta que está creando hacia el recurso no es del todo correcta.

En tiempo de diseño el entorno no sabe qué URL será utilizada para acceder a la página, por lo que incluye en el código es la ubicación relativa del recurso respecto a la ubicación de la vista actual en el sistema de archivos.

Por ello, en el ejemplo anterior, editando el archivo /Views/Home/Index.aspx ha generado la ruta relativa hacia la carpeta Content, que incluye dos saltos hacia arriba en la estructura de carpetas para llegar al raíz, más el acceso al archivo desde éste.

Esto puede ser válido si estamos editando páginas en un entorno en el que las peticiones son mapeadas directamente contra el sistema de archivos, pero no en MVC, donde las rutas son tan fácilmente manipulables.

De la misma forma, tampoco sería válido en escenarios WebForms donde la ubicación de la página no coincida con la de la petición actual, como las páginas maestras o controles de usuario, o si utilizamos las nuevas capacidades de routing de .NET 4.

Volviendo de nuevo al ejemplo anterior, aunque la vista esté implementada en el archivo  /Views/Home/Index.aspx, el acceso a la misma podría realizarse, utilizando la ruta por defecto, mediante la URL http://servidor/, lo que implica que la referencia relativa de la hoja de estilos estaría saliéndose del ámbito de la aplicación, es decir, se estaría intentando acceder dos niveles por arriba de la carpeta de publicación del proyecto.

En el servidor web integrado en Visual Studio nuestra aplicación funcionará correctamente al ignorar los intentos de subir más allá del raíz de la aplicación, lo que retrasa la detección del problema. Al publicar en IIS, bastante menos permisivo, nos encontraremos con que nuestra aplicación ha dejado de funcionar.

Afortunadamente hay soluciones para todos los gustos. De hecho, más que soluciones para cuando aparezca el problema, deberíamos tomarlas como buenas prácticas a la hora de referenciar cualquier tipo de elemento desde el principio del desarrollo.

Veamos algunas de ellas.

Solución 0: Cambiar las rutas a mano

La “solución” más artesana es, sin duda, introducir manualmente las rutas en todas las referencias hacia recursos externos de la vista. De hecho, en realidad nos puede ayudar a solucionar el problema descrito anteriormente, pero es bastante poco flexible, y no muy recomendable.

Así, el ejemplo anterior podríamos editar el código generado por Visual Studio y sustituirlo por el siguiente:

<link href="/Content/Site.css" rel="stylesheet" type="text/css" />

Como observaréis, hemos eliminado la porción “../../” de la ruta, por lo que la hoja de estilos ya estaría referenciada correctamente, ¿no?

Pues depende. Si nuestra aplicación se publica en el raíz de un dominio o subdominio, todo será correcto; en cambio, si queremos desplegarla en un directorio ya la hemos vuelto a liar, puesto que la referencia asume que la carpeta “Content” se encuentra en el raíz.

Por experiencia, suele ser bastante habitual que durante el desarrollo de una aplicación se cuelguen versiones de demostración en directorios privados, y una vez terminada se pasen al raíz de su dominio. Ante este escenario, si las rutas las hemos indicado de forma absoluta, en vez de una solución, hacer este cambio es sólo introducir una nueva fuente de problemas.

Solución 1: Usar el helper Url.Content()

El helper Url.Content() nos permite obtener la URL del recurso cuya ubicación física estamos pasándole como parámetro. Dado que el resultado se calcula en tiempo de ejecución, el framework ya dispone de información suficiente para generar la dirección correcta.

La forma de usarlo, muy sencilla. Observad el uso del gusanillo “~” para hacer referencia al directorio raíz de la aplicación:

<link href="<%= Url.Content("~/Content/Site.css")%>" rel="stylesheet" type="text/css" />
<script src="<%= Url.Content("~/Scripts/jquery-1.4.1.js")%>" 
        type="text/javascript" /></script>

Este enfoque sí aporta una solución definitiva al problema, aunque a la hora de codificarlo sea algo tedioso.

Solución 2: usar T4MVC

Otra alternativa, sin duda interesante, para generar la ruta correcta es utilizar la magnífica herramienta T4MVC, de la que ya hemos hablado por aquí algunas veces. Muy resumidamente, T4MVC es una plantilla de generación de código automático capaz de analizar el contenido de nuestro proyecto y generar “constantes” que nos permitan eliminar los literales de texto en las aplicaciones MVC.

Así, por ejemplo, tras su inclusión en nuestro proyecto, la propiedad pública  Links.Content.Site_css contendrá la ruta correcta hacia el archivo ~/Content/Site.css, calculada en tiempo de ejecución, por lo que podríamos dejar el código anterior en:

<link href="<%= Links.Content.Site_css %>" rel="stylesheet" type="text/css" />
<script src="<%= Links.Scripts.jquery_1_4_1_js %>" 
        type="text/javascript" /></script>

Observad que hemos eliminado la llamada a Url.Content(), puesto que ya las propiedades utilizadas están calculando la ruta correcta.

Una ventaja adicional de T4MVC es que podría detectarse en tiempo de compilación la ausencia de un archivo. Si después de introducir el código anterior eliminamos los archivos referenciados, al compilar la vista se produciría un error. Además, durante la codificación podemos disfrutar de intellisense para descubrir los archivos y evitar errores.

Solución 3: Crear nuestros propios helpers

Ya sabemos que el framework ASP.NET MVC está, desde sus inicios, preparado para ser fácilmente extendido, y los helpers Html de las vistas no iban a ser la excepción.

Si por cualquier extraño e incomprensible motivo no quieres o puedes utilizar T4MVC, siempre podrías construirte tus propios helpers. En el siguiente ejemplo, vemos cómo con un par de llamadas podríamos simplificar la generación de las etiquetas de referencia a scripts y estilos en una página:

<head>
<title>Mi sitio web</title>
<%= Html.IncludeStyles("site.css", "ui.jqgrid.css", "redmond/jquery-ui-1.8.2.custom.css")%>
<%= Html.IncludeScripts("jquery-1.4.1.min.js", "jquery-ui-1.8.2.custom.min.js", 
                        "grid.locale-sp.js", "jquery.jqGrid.min.js")%>
</head>

Como se puede intuir, estos helpers generarán las etiquetas <style> y <script> correspondientes para todos los archivos que se les suministre como parámetros. El código, el siguiente:
 
public static class HtmlIncludeHelpers
{
    public static MvcHtmlString IncludeScripts(this HtmlHelper html, 
                                               params string[] scriptNames)
    {
        return generateContent(
                    html,
                    @"<script type=""text/javascript"" src=""{0}""></script>",
                    "~/Scripts/",
                    scriptNames
        );
    }
 
    public static MvcHtmlString IncludeStyles(this HtmlHelper html, 
                                              params string[] fileNames)
    {
        return generateContent(
                    html,
                    @"<link href=""{0}"" rel=""stylesheet"" type=""text/css"" />",
                    "~/Content/",
                    fileNames
        );
    }
 
    private static MvcHtmlString generateContent(HtmlHelper helper, string tag, 
                                                 string root, IEnumerable<string> files)
    {
        StringBuilder sb = new StringBuilder();
        if (files != null)
        {
            string path = UrlHelper.GenerateContentUrl(root, helper.ViewContext.HttpContext);
            foreach (var file in files)
            {
                sb.AppendFormat(tag, Path.Combine(path, file));
            }
        }
        return MvcHtmlString.Create(sb.ToString());
        
    }
}


En definitiva, existen mil y un patrones que podemos utilizar para evitar problemas en la generación de rutas hacia los recursos de una página. Espero que lo planteado en este post puedan seros de ayuda a la hora de diseñar vuestra propia solución.

Publicado en: Variable not found.
domingo, 5 de septiembre de 2010
Por mucho que nos las merezcamos y queramos alargarlas hasta el infinito, las vacaciones también tienen que terminar. Gracias a esto mantenemos la ilusión y ganas de que lleguen las próximas, ¿no? ;-)

Así que, tras unos días de reentrada suave, aquí estamos de nuevo. Con las pilas a tope y listos para comenzar una nueva temporada que seguro será magnífica… a pesar de la que está cayendo ahí fuera.

Queda, pues, inaugurada la temporada 2010-2011 de Variable Not Found, donde espero contar, como siempre, con vuestra compañía y apoyo.

¡Nos vemos por aquí!

Publicado en: Variable not found.
lunes, 26 de julio de 2010
Hace unos días he iniciado las vacaciones, y con ellas el descenso de actividad tradicional en Variable not found (bueno, y en esta ocasión también podréis notarlo en Facebook y Twitter), por lo que dejaré de daros la lata durante algún tiempecito.

El PortilComo en otras ocasiones, los destinos elegidos para descansar son El Portil, una tranquila playa en la provincia de Huelva, y Sanlúcar de Barrameda, una maravillosa localidad costera de Cádiz.

Aunque seguiré atento al mail y no voy a dejar de trabajar durante este tiempo (ya os comentaré el nuevo proyecto que me traigo entre manos), sí que relajaré el tiempo de dedicación con objeto de recargar las pilas para el próximo año que, según se está planteando, será de lo más emocionante.

Dejo cerrado los comentarios anónimos para evitar que los spammers conviertan esto en un festival de enlaces a sitios inapropiados. Ah, no, no hace falta… ya los había cerrado hace algunas semanas precisamente por eso, así que nada. ;-P

Nos vemos a la vuelta.

Felices vacaciones, amigos ;-)

Publicado en: http://www.variablenotfound.com/.
miércoles, 14 de julio de 2010
Variable not found es un blog cuyos lectores son en su mayoría esporádicos y proceden de motores de búsqueda: aterrizan, miran lo que les interesa, se van, y la mayoría de ellos no vuelven. Obviamente estos usuarios son bienvenidos y alegra saber que cada día los posts de VNF llegan a más gente.

Sin embargo, el dato que siempre he valorado más para hacerme una idea de la aceptación de un blog es el número de suscriptores a los feeds, puesto que implican una respuesta activa del lector hacia los contenidos. Se trata de personas que, voluntariamente, deciden en un momento u otro añadirte como fuente a su lector favorito, mostrando así de forma explícita su interés por tu trabajo.

Y aunque sé que Feedburner no es demasiado preciso, que este dato suele oscilar bastante y que probablemente en unas horas ya no será así, me váis a permitir que lo celebre un poco...

¡Hemos superado los mil suscriptores a los feeds en Variable not found! :-))

1029 suscriptores en Variable not found

¡Mil gracias a todos!

Publicado en: Variable not found
martes, 13 de julio de 2010
Elegir elementos para la caja de herramientasHacía tiempo que Visual Studio 2008 me estaba dando problemas al intentar añadir controles a la caja de herramientas. Concretamente, tras pulsar el botón derecho del ratón sobre esta zona y seleccionar la opción “Elegir elementos”, el entorno se cerraba bruscamente sin dar ningún tipo de explicación.

Aunque hasta ahora he podido convivir pacíficamente con este problema (básicamente, no añadiendo controles al Toolbox ;-)), hace unos días decidí dedicar un rato a solucionarlo.

En primer lugar, dado que el casque no mostraba ningún mensaje de error previo, he acudido al visor de eventos de Windows, encontrándome con el siguiente mensaje:
.NET Runtime version 2.0.50727.3603 - Error grave de motor de ejecución (7A036050) (80131506)
Instalando el hotfixAfortunadamente, es una pista suficiente para dar con la solución. Googleando un poco los códigos de error 7A036050 y 80131506, he dado con el hotfix KB963676, que es posible descargar desde Microsoft Connect.

Una vez instalado el software apropiado para nuestra plataforma (x86, x64…) y reiniciado el equipo, todo ha vuelto a la normalidad.

Y es que a veces bastan unos minutos para eliminar esos pequeños y molestos inconvenientes que nos hacen menos productivos. Lo que es la procrastinación ;-)

Publicado en: Variable not found
Twitteado en: twitter.com/jmaguilar
Facebookeado en: facebook.com/variablenotfound
lunes, 12 de julio de 2010
Estos son los enlaces publicados en Variable not found en Facebook desde el lunes, 05 de julio de 2010 hasta el domingo, 12 de julio de 2010. Espero que te resulten interesantes. :-)
Y no olvides que puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.

Publicado en: Variable not found
miércoles, 7 de julio de 2010
WebMatrix Ayer mismo ScottGu anunciaba la publicación de la primera beta de WebMatrix, una curiosa, y por mi parte inesperada, solución integrada cuyo objetivo es facilitar el acceso al desarrollo de aplicaciones Web con tecnologías Microsoft, y principalmente, según parece, al desarrollador novel o procedente de otras plataformas.

WebMatrix se puede descargar de forma gratuita desde este enlace, y la instalación se realiza en unos minutos. Una vez completado el proceso, no requiere ningún tipo de registro del usuario, ni obtención de claves, simplemente funciona.  Instalación con WebPI
¿Y qué vamos a encontrar tras la instalación? En primer lugar, hay que destacar que WebMatrix no es sólo una herramienta de desarrollo; podríamos decir que es un pack que incluye tanto las herramientas como lStack Webmatrixas plataformas necesarias para desarrollar, probar y desplegar aplicaciones para la web: IDE, repositorio de proyectos open source de partida, motor de datos, servidor web, y un nuevo framework de desarrollo sobre ASP.NET. Y todo ello integrado de forma muy elegante.

Veamos en mayor detalle cada uno de estos elementos.

El entorno WebMatrix

Una vez instalado el paquete, en nuestro menú de aplicaciones encontraremos un acceso directo a WebMatrix, que actuará como centro de control para el resto de sistemas integrados en el paquete, y como nuestro entorno de desarrollo.

Una vez iniciado, a la hora de crear proyectos, podemos hacerlo desde cero o hacerlo desde distintos puntos de partida:
  • partiendo de plantillas suministradas con WebMatrix, entre las que se encuentran un directorio de enlaces, un catálogo simple de productos o una galería fotográfica, entre otros.

    Plantilla de proyecto: Directorio de Enlaces
  • crearlas partiendo de algún software existente en una galería de software libre, la misma utilizada por Web Platform Installer. Para ello, sin salir del entorno, podremos seleccionar la plataforma deseada, y será descargada e instalada automáticamente. Es destacable que, además de la aplicación elegida, se instalarán también las dependencias requeridas (por ejemplo PHP, o el motor MySQL).

    Crear un proyecto desde la Web Gallery
Ya sobre un proyecto abierto, el uso de WebMatrix se estructura en torno a cuatro espacios de trabajo, Site, Files, Databases y Reports, que se describen a continuación:
  • Site, desde el que se pueden consultar y modificar aspectos generales sobre el proyecto, y acceder a herramientas como el gestor de datos, el generador de informes del sitio web, un visor de peticiones, o aspectos relativos al despliegue. Incluso es posible acceder a ofertas de alojamiento de nuestros sitios Web.
  • Files, que da acceso a la estructura de carpetas y a los archivos de nuestro proyecto, y desde donde es posible crear, editar y añadir contenidos. En la siguiente captura se muestran algunos tipos propuestos al añadir un nuevo fichero al proyecto:imageComo editor de código el entorno se queda bastante cortito, no tiene nada que ver con cualquiera de las ediciones de Visual Studio. De hecho, salvo el coloreado de código (disponible para HTML, CSS, Javascript, PHP, y ASP.NET), poco tiene que envidiarle el block de notas de toda la vida: nada de ayudas, autocompletado, intellisense o similares, dado que la orientación de WebMatrix es distinta, bastante más simple en este aspecto, a entornos de desarrollo profesionales. Por tanto, para desarrollar en serio debes pasar a Visual Studio, incluso en su versión Express, que superarán en mucho a esta herramienta.

    Sin embargo, puede ser suficiente para desarrolladores que simplemente deseen retocar aplicaciones basadas en las plantillas suministradas, o software libre, que puede ser descargado directamente desde la herramienta, o usuarios que estén iniciándose en esta tecnología.

  • Databases, desde donde es posible gestionar las bases de datos utilizadas por el proyecto. En este momento dispone de soporte completo para SQL Server, MySQL y, otra gran novedad en WebMatrix, la nueva edición de SQL Server Compact Edition, que comentaré un poco más adelante.image
  • Reports, una herramienta que nos permite generar informes SEO sobre el sitio Web, capaz de analizar el sitio web de la misma forma que lo hace el toolkit SEO para IIS, para indicarnos aspectos errores y aspectos mejorables vistas a la optimización en buscadores.Informes SEO

IIS Express

ScottGu anunció hace unos días la próxima disponibilidad de IIS Express, un intento de mezclar la potencia de IIS 7.5 y la facilidad de uso de los servidores de desarrollo que estamos acostumbrados a utilizar desde Visual Studio. Lo mejor de los dos mundos.

image Y aquí lo tenemos. Los sitios web abiertos desde WebMatrix son ejecutables directamente a través de este servidor, que iniciará al abrir el proyecto y quedará minimizado en el área de notificaciones de Windows.

Desde este icono podemos consultar las aplicaciones actualmente en funcionamiento en el servidor, consultar información básica sobre ellas, como la ruta desde la que se está sirviendo, resetearlas, y algunas cosas más.

El comportamiento de las aplicaciones sobre IIS Express es idéntico a como sería en los servidores de producción con el correspondiente IIS 7.5, puesto que internamente se utiliza el mismo motor, evitándonos así la necesidad de contar con permisos de administrador, tener el servicio corriendo continuamente, o el engorro de configurar cada aplicación (permisos, pool de aplicaciones, etc.).

Desde el entorno de WebMatrix también podemos iniciar, parar, o resetear el servidor Web, así como, y esto es un detalle de lo más interesante, consultar en tiempo real las peticiones que se están produciendo a nuestra aplicación, muy útil en depuración:
image

SQL Server Compact Edition 4

Otra de las grandes novedades introducidas en WebMatrix fue también presentada hace unos días por el mismo Scott Guthrie: SQL Server Compact Edition (SQL CE), una versión reducida del motor de bases de datos de Microsoft diseñada para funcionar en el interior de aplicaciones ASP.NET.

SQL CE es un motor ideado para ser la forma más fácil de incluir bases de datos en aplicaciones, eliminando los altos requisitos asociados a ello: es gratuito, y no requiere ningún servicio en el servidor, lo cual reduce los costes finales de alojamiento.

¿Y cómo es posible esto? Pues en primer lugar, haciendo que el motor sea basado en archivo; para mover datos entre un sitio y otro bastará con copiar el fichero de datos, como si se tratara de un Access. Asimismo, el motor se distribuye con la aplicación, y se ejecuta en memoria junto con ésta. De hecho, para desplegar un proyecto que use esta solución como repositorio de datos bastará con copiar unas DLLs en el directorio de binarios de la aplicación, y lo tendremos todo listo.

Como consecuencia, nada que instalar en servidor, ni se requieren privilegios especiales para ejecutarlo.

A nivel de programación es compatible con las API de acceso a datos de .NET, lo que quiere decir que no debemos encontrar problemas para utilizar tecnologías de mayor nivel como Entity Framework u otros ORMs. Sus únicas limitaciones vienen dadas por el tamaño de fichero máximo admitido (en estos momentos 4GB, aunque se prevé subir esta cifra) y por la ausencia de determinadas características como los procedimientos almacenados, o triggers, entre otros.

Y aunque está claro que el rendimiento no será comparable al de otras ediciones de SQL Server, y que no podrá aguantar una gran carga de usuarios, es posible upgradearla (a Express, Server o incluso Azure) sin tocar una línea de código. De hecho, desde el propio entorno de WebMatrix se dispone de herramientas para realizar la migración:

Migración de una base de datos SQL CE a SQL Server
En WebMatrix existe una integración total con este nuevo motor de datos. Sin salir del entorno es posible agregar bases de datos al proyecto, editar su estructura, acceder a los datos, o manipular su diseño y propiedades:

SQL Server CE en WebMatrix

ASP.NET Web Pages & Razor

ASP.NET Web Pages es un nuevo framework de desarrollo, presentado con WebMatrix, destinado a la creación de aplicaciones sencillas para la Web. Y con “framework nuevo”, me refiero a eso precisamente… es diferente a WebForms, y también diferente a la alternativa ASP.NET MVC:
  • no soporta controles de servidor
  • no mantiene el estado de la vista (ViewState)
  • no hay eventos
  • no hay code-behind
  • no hay separación de capas arquitectural, como en MVC
  • no hay convenciones de nombrado o localización
  • no hay tabla de rutas...
Lo único que hay es la página, como en los viejos tiempos.

De hecho, al echarle un vistazo, no se puede evitar la sensación de estar ante algo con cierto aire retro, muy parecido a la programación con ASP clásico (sin .NET), PHP, JSP u otros lenguajes basados en el concepto de “todo está en la página”, aunque, eso sí, apoyado en el framework .NET, con las ventajas que ello conlleva.

Programación con ASP.NET Web Pages
ASP.NET Web Pages Dispone de un API propio (todavía algo escaso de documentación, estamos en Beta), con un gran número de funciones y helpers, algunos de ellos muy potentes, para facilitarnos el desarrollo. Por citar sólo algunos ejemplos, tendremos acceso a funcionalidades de alto nivel de Twitter o Facebook, inclusión directa de vídeos, validaciones con ReCaptcha, o manipulación de imágenes, utilizando helpers dentro de la propia página.

Por defecto utiliza el motor de vistas Razor, uno de los previsibles grandes cambios del próximo ASP.NET MVC 3, donde también será el ViewEngine por defecto.

Razor está diseñado para integrarse de forma más natural en el código de las páginas, siendo más conciso y expresivo que el utilizado hasta ahora. Pero sin duda, lo más destacable de este motor de vistas es que cambia la forma en la que incluimos código en el interior del marcado de una página: los clásicos bloques <%%> que usamos desde hace muchos años y que contribuyen a dificultar la lectura son sustituidos por una nueva estructura, que se apoya en un parser mucho más inteligente y sensible al contexto, y que nos permite introducir código como el siguiente:

Código fuente Razor
Estas dos tecnologías, ASP.NET Web Pages y Razor, aunque pueda parecer lo contrario, son totalmente independientes entre sí, aunque se combinen por defecto en WebMatrix. De hecho, existirán otros motores de vistas para Web Pages, y Razor podrá ser utilizado en otros contextos, como el framework MVC.

Destaca también el hecho de que Razor ni siquiera depende del contexto Web para funcionar, lo que deja la puerta abierta a su inclusión en otros tipo de aplicaciones, o incluso a la realización de pruebas unitarias sobre la vista.

¿Conclusiones?

El concepto WebMatrix, como suma de plataformas y herramientas que ofrecen una vía rápida para la creación o personalización de aplicaciones, sobre todo si están basadas en paquetes existentes como software libre, me parece muy interesante.

Como entorno de codificación es obvio que se queda muy corto. Pero claro, tampoco habría tenido sentido para Microsoft crear un nuevo IDE, que dispone ya de Visual Studio y su magnífica versión Express, que también es gratuita. Como comentaba anteriormente, este entorno sirve para los casos en los que también te podría valer el Notepad, poco más o menos.

Sin embargo, sí me ha parecido muy correcta la integración en el entorno de las herramientas de gestión de bases de datos, el servidor web integrado, el sistema de deployment y el analizador SEO, y la pasmosa facilidad de instalación y uso del conjunto. Realmente, en sólo unos minutos puedes descargar un software open source, probarlo en local y subirlo a tu ISP, casi sin conocer lo que hay por detrás.

Para noveles o ajenos a tecnologías de Microsoft es una vía interesante para acceder a ella, aunque sea a través de un camino que no existía hasta ahora, y con un destino distinto a los conocidos hasta el momento, y que tendrá que demostrar su validez en la práctica. Lo que es seguro es que la sencillez de la propuesta hará que la curva de aprendizaje sea relativamente suave.

También lo considero interesante para los que ya llevamos algunos años en esto, pues materializa la posibilidad de dar un vistazo a varias novedades de calado que ya se venían comentando desde hace algún tiempo, como Razor, IIS Express, o SQL CE, y que seguro que entrarán en breve a formar parte de nuestras herramientas de uso habitual.

Respecto a ASP.NET Web Pages, en cierto sentido puede entenderse como un paso atrás… siempre que estés delante, claro ;-). Hay muchos desarrolladores que todavía luchan a diario con ASP clásico o cualquier otra plataforma de las mismas características, a los que saltar a esta tecnología seguro que costará menos trabajo que pasar a Webforms, pues las diferencias son mucho menores.

Enlaces:
Publicado en: Variable not found.