Implementar un sitio web privado con ASP.NET MVC

24. December 2011 20:44 by Oscar.SS in Desarrollo Web  //  Tags: ,   //   Comments (5)

Bueno, para terminar el año operativo de este blog que mejor que un artículo de los facilitos. No es cuestión ya en estas fechas de complicarse la vida. Jejeje...que disculpas me pongo ;-)

Vamos a implementar con ASP.NET MVC la funcionalidad mínima para que un sitio web sea privado a todos los usuario no registrados. Utilizaremos la autentificación de usuarios por formulario y veremos como podemos aprovechar parte del código de la plantilla de aplicación que viene por defecto cuando creamos un nuevo proyecto ASP.NET MVC. Por otra parte crearemos un filtro personalizado que será el encargado de gestionar que usuarios tienen acceso para ejecutar un controlador o método de acción, o lo que es lo mismo, que usuarios tienen permiso para visualizar una vista concreta.

 

Paso 1. Creamos un nuevo proyecto ASP.NET MVC de tipo Internet Application

Seguramente el lector ya iniciado conocerá de sobra que esta plantilla de ASP.NET MVC contiene una funcionalidad mínima de un sitio web con un par de páginas y autenticación de usuarios por formulario que es precisamente la parte que nosotros vamos a reutilizar para el caso que nos ocupa. La validación de las credenciales de los usuarios que viene por defecto en esta plantilla utiliza el sistema de membresía de ASP.NET, el cual, nosotros vamos a sustituir más adelante.

 

Paso 2. Cambiar la ruta por defecto en el Global.asax

Parece lógico pensar que si todo el sitio web va a ser privado deberíamos iniciar la aplicación directamente en el formulario de login para que los usuarios escriban sus credenciales. Seguramente el lector ya sabrá que en el Global.asax existe un método RegisterRoutes() que es invocado al iniciar la aplicación para crear la tablas de rutas que utilizará el sistema de routing. En ese método podemos especificar que la ruta por defecto para nuestra aplicación será el formulario de login.

            routes.MapRoute(
                
"Default"// Route name
                
"{controller}/{action}/{id}"// URL with parameters
                
new { controller "Account", action "LogOn", id UrlParameter.Optional } // Parameter defaults
            
);

 

Paso 3. Validación de usuarios personalizada

Aquí es donde vamos a sustituir el sistema de membresía de ASP.NET por un método de validación de usuarios personalizado. Vayamos al controlador AccountController y modifiquemos de la siguiente forma el método de acción LogOn que maneja las peticiones por HTTP POST.

        public ActionResult LogOn(LogOnModel model)
        {
            
if (ModelState.IsValid)
            {
                
if (UserServices.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe)
;

                    return 
RedirectToAction("Index""Home");
                
}

                ModelState.AddModelError(
"""The user name or password provided is incorrect.");
            
}

            
// If we got this far, something failed, redisplay form
            
return View(model);
        
}

Si comparamos este código con el que viene por defecto veremos que tan solo se han modificado dos cosas. En primer lugar se ha eliminado el parámetro returnUrl (así como la comprobación de su formato) del método de acción. Cuando la autentificación de usuarios se gestiona directamente desde el Web.config, como hemos hecho siempre en ASP.NET, este parámetro contiene la ruta a la que intentaba navegar el usuario no autentificado. Dado que nosotros vamos efectuar este proceso por medio de un filtro global, no haremos uso de este parámetro.

En segundo lugar, hemos sustituido la validación de las credenciales del usuario por medio de la clase Membership por un sistema propio de validación. Vamos, esto no es más que un método que llame a nuestra base de datos, en este caso UserServices.ValidateUser(), y compruebe si existe un usuario con estas credenciales, y ya de paso que compruebe que este sea único...¡por si las moscas! :-)

 

Paso 4. Limpiamos el web.config

Por defecto el web.config viene configurado para hacer uso del sistema de membresía que hemos dicho que no vamos a utilizar, así que eliminamos del web.config las siguiente secciones.

  <!--Sustituimos la cadena de conexión que viene por defecto por la que corresponda-->
  
<connectionStrings>
    
<add name="ApplicationServices"
         connectionString
="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
         providerName
="System.Data.SqlClient" />
  </
connectionStrings>

  
<!--Administración y autenticación de cuentas de usuario-->
  
<membership>
    
<providers>
      
<clear/>
      
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
           enablePasswordRetrieval
="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
           maxInvalidPasswordAttempts
="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
           applicationName
="/" />
    </
providers>
  
</membership>

  
<!--Configuración de los valores de los perfiles de usuario-->
  
<profile>
    
<providers>
      
<clear/>
      
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
    </
providers>
  
</profile>

 

Paso 5. Codificamos un filtro

El propio framework de ASP.NET MVC nos ofrece una serie de filtros  permitiéndonos la ejecución de código de forma limpia a modo de atributos declarativos. Como en otras ocasiones ASP.NET MVC nos permite extender el framework escribiendo un filtro personalizado que utilizaremos para permitir el acceso o no de los usuarios a los distintos recursos de la aplicación.

    public class RequiredAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
    {
        
/// <summary>
        /// Determina si va a realizar la comprobación de autenticación para un método de acción o 
        /// controlador. Por defecto es true.
        /// </summary>
        
public bool Check { get; set; }

        
public string Controller { get; set; }
        
public string Action { get; set; }

        
public RequiredAuthenticationAttribute()
        {
            Check 
= true;
        
}

        
public void OnAuthorization(AuthorizationContext filterContext)
        {
            
//Si es false no se realiza la comprobación de autenticación
            
if (!Check) return;

            
var routeValueDictionary = new RouteValueDictionary(
                
new
                    
{
                        
//El operador doble interrogación se invierte por validaciones de script en este blog
                        
action Action ¿¿ "LogOn",
                        controller 
Controller ¿¿ "Account"
                    
});

            if 
(!filterContext.HttpContext.Request.IsAuthenticated)
                filterContext.Result 
= new RedirectToRouteResult(routeValueDictionary);
        
}
    }

 

Paso 6. Registramos el filtro globalmente

Como nuestra intención es que todo el sito web sea privado para todos aquellos usuarios no registrados, en el Global.asax añadimos el filtro a la colección de filtros globales de ASP.NET MVC, de esta forma antes de ejecutar cualquier controlador se ejecutará el código de nuestro filtro personalizado. Y si el usuario que ejecuta el controlador no esta autenticado le devolverá siempre a la vista de login.

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(
new HandleErrorAttribute());
            
filters.Add(new RequiredAuthenticationAttribute());
        
}

 

Paso 7. Definir métodos públicos a todos los usuarios

En el paso anterior hemos establecido que se ejecute el código de nuestro filtro antes de ejecutar cualquier controlador o método de acción. Pero tenemos que permitir el acceso al formulario de login a todos los usuarios para que puedan escribir sus credenciales. Para ello firmamos los dos métodos de acción (GET y POST) que gestionan el formulario de autenticación de usuarios.

        [RequiredAuthentication(Check = false)]
        
public ActionResult LogOn()
        {
            
return View();
        
}

        [HttpPost]
        [RequiredAuthentication(Check 
= false)]
        
public ActionResult LogOn(LogOnModel model)
        {
            
//Aquí va el código que hemos modificado en el paso 3
        
}

Como se puede observar, utilizamos el filtro y establecemos a false la propiedad Check para que todos los usuarios tengan permiso para visualizar y enviar el formulario de login. También podríamos especificar por medio de las propiedades Controller y Action del atributo un formulario de login distinto al de por defecto para redirigir a los usuarios que no tengan credenciales. 

 

Paso 8. Proteger carpetas y archivos

Con lo visto hasta ahora ya tendríamos la funcionalidad mínima para comprobar la autenticación de los usuarios. Pero supongamos que nuestra aplicación contiene documentos PDF, imágenes o cualquier tipo de archivo sensible de ser protegido. Dado que nuestro filtro sólo protege el contenido entregado por el propio método de acción, debemos especificar en el Web.config que carpetas o archivos deben ser protegidos. 

Por ejemplo, en el caso de una carpeta que contiene las fotos de los usuarios, si queremos que estas no sean accesibles directamente por URL a todos los usuarios debemos configurar la aplicación para protegerlas.

  <location path="UserPhotos">
    
<system.web>
      
<authorization>
        
<deny users="?"/>
      </
authorization>
    
</system.web>
  
</location>

 En combinación con los elementos location y deny, especificamos que el directorio que contiene las fotos de los usuarios sólo será accesible para los usuarios que ya se han registrado e identificado. Esta forma de proteger directorios no es exclusiva de MVC, de hecho, es la forma tradicional de hacerlo en ASP.NET.

Para finalizar mencionar que todo lo que hemos visto tan solo es un sencillo ejemplo para intentar mostrar algunos conceptos como los filtros, extensión del framework o la gestión de usuarios por formulario. De todas formas puede ser válido para pequeñas aplicaciones con pocos usuarios, pero para aplicaciones de más envergadura habría que realizar algo más de trabajo como por ejemplo con la gestión de roles.

Bueno, espero que a pesar de su sencillez le pueda servir a alguien para acercarse un poco más ASP.NET MVC y a todo lo que contiene.

¡¡Felices fiestas y hasta el año que viene!! :-)

 

Actualización 01/02/2013

Dado que varias personas me han pedido el código de la aplicación lo dejo aquí para descarga. En el encontraréis una solución ASP.NET MVC 3 con dos proyectos.

- ByCodingFilter. Este es el mismo proyecto que se ha visto a lo largo de este artículo.

- ByConfiguración. Establece la autorización por configuración en el web.config

PrivateMvcWebsite.rar (9.35 mb)

Crónica del Life Is Soft 2011

12. November 2011 00:26 by Oscar.SS in Información, Personal  //  Tags: ,   //   Comments (9)

Ayer tuve la suerte de poder asistir al "Life Is Soft 2011" que este año se ha celebrado en la ciudad Asturiana de Gijón. Creo recordar que hacía más de 25 años que no visitaba esta ciudad y la verdad la he encontrado muy bonita y limpia. Ni siquiera el día nublado y tímidamente lluvioso han estropeado los bellísimos paisajes naturales o la espectacular arquitectura de sus edificios emblemáticos.

Patio de la Universidad Laboral En cuanto al evento en sí, se ha celebrado en el Teatro Principal de la Universidad Laboral. Nunca había visitado el centro universitario de Gijón y sinceramente tengo que decir que me ha causado una agradable impresión. Es un edificio espectacular, bien cuidado y acondicionado.

La temática del Life Is Soft no es esencialmente técnica. Está más dirigida a todo lo que ocurre alrededor, e incluso después, del proceso de codificación. Como vender el software, el equipo humano, diseño y todo aquello que muchas veces los técnicos (me incluyo por supuesto) no damos la debida importancia. Pero la tiene, sobre todo si realmente pretendes hacer de tu código un negocio. Por lo menos a mí, me ha parecido interesante empaparme de estos conceptos más globales y externos al código que evidentemente mueven nuestra industria.

La dinámica de Life Is Soft ha sido una sorpresa agradable en cuanto a su ejecución. Los ponentes se sucedían unos detrás de otros con solo 12 o 15 minutos para comunicar sus experiencias y "penas". Y como director de la línea del tiempo, haciendo las veces de maestro de ceremonias, se encontraba Mario Conde. Este tipo de ejecución, al estilo de los monólogos televisivos, ciertamente son muy ágiles, entretenidas y creo yo más comunicativas si cabe. Mejor quedarte con una sola idea en 15 minutos que un par de bostezos en 1 hora.

A continuación os resumo muy brevemente algunas de las presentaciones por si es de vuestro interés.

¿Cómo ser rentable en una empresa de software?

Santiago Cabaleiro apunta que el éxito del software está en focalizar. Focalizar en el cliente (o el usuario), saber realmente cual es su necesidad o que es lo que más valora. Por otra parte focalizar en lo que mejor hace tu empresa y de estas habilidades focalizar en las que hacemos mejor que la competencia. Hay que pensar a largo plazo y para mantener el foco durante un largo periodo es necesaria implicación, indicadores (métricas) e ingresos periódicos.

 

Playa de San Lorenzo Las personas trabajando a gusto damos lo mejor

La presentación de Lola Calvo tengo que reconocer que ha sido una bocanada de aire fresco. No recuerdo ningún evento de software, ni de ningún otro tipo, ya sea técnico o empresarial, en los que se hiciera una sola mención al equipo humano que evidentemente se encuentra detrás de todo lo que hacemos. Desde luego para una empresa conseguir y retener un buen equipo humano con talento es vital, pero para nosotros, sentir que la empresa tiene en cuenta a las personas y no solo a los números, es decisivo.

Aunque parezca mentira, apuntaba que las empresas debería tener en cuenta conceptos como respeto, confianza, que ofrece la empresa (captación), economía, familia (tiempo libre), salud, las necesidades de las personas cambian con el tiempo (desarrollo), esfuerzo por retener el talento, etc.

¿A que parece una utopía?, y seguramente lo sea. Si encuentro una empresa de software que realmente tiene en cuenta solo la mitad de estos factores...¡me caso con ellos!

 

Evolucionamos en tecnología para innovar en software

Hablando de los rápidos y continuos cambios tecnológicos que sufrimos los que trabajamos con software, David Gutiérrez aconseja intentar ser el más adaptado, no el más grande. Siempre que sacamos una nueva versión de producto aumentamos la funcionalidad, comenta que es preciso también quitar funcionalidad para una mejor adaptación.

 

Diseño

Y como no podía ser de otra forma el diseño también estuvo presente. Bueno, no hay mucho que comentar sobre esto, es evidente que si el destino final de tu software va a ser usado por personas, debe tener un aspecto bonito y también usable. Nicolás Osuna comentó un dato que me pareció curioso: según Apple y Google si un campo no es utilizado por al menos el 80% de los usuarios hay que eliminarlo.

 

Ponencia de José Manuel AlarcónLa venta de software

Finalmente el destino de todo software es la venta, ya sea económicamente o a cambio de otros intereses o servicios. Cecilio Labrada habló sobre un modelo clásico de ventas, AIDA, que naturalmente yo no conocía pero me pareció curioso.

 

¡No hagas eso! Los dos errores más graves en las PYME tecnológicas a la hora de vender

Un regalo muy valioso los dos consejos de José Manuel Alarcón sacados directamente de su experiencia profesional como empresario.

Falta de diferenciación. Las PYME deben de competir en el ámbito de la especialización olvidándose de conceptos como solución integral. Es un error, sobre todo cuando se empieza, intentar abarcarlo todo. ¡Especialízate y concreta!

Competir en precio. Cuando una PYME se intenta posicionar con precios bajos condiciona muchos sus márgenes y obtiene un mal posicionamiento por marketing. Además tus competidores directos siempre pueden hacer lo mismo y en cuanto a las empresas grandes tienen mayor pulmón financiero para resistir la guerra de precios.

 

Marketing online: Redes sociales

Sobre las redes sociales y las empresas, personalmente lo extendería también a las personas, Fernando Maltrana nos habló de su importancia pero también de su conveniencia en según qué casos.

Resumiendo mucho redacto los puntos claves que se comentaron. Estrategia (hay que tener un objetivo), audiencia (contar y escuchar), autenticidad, privacidad (¿le interesa a todos lo que publico?), constancia y equilibrio (no abrumar), coherencia y tráfico medible.

 

Con estas vistas me desperté yo!! Fear Uncertainty and Doubt

Marcos Eguillor nos presentó un concepto de estrategia comercial que me sorprendió bastante. No porque no me lo esperaba, más bien porque sea una estrategia reconocida, estudiada y medible. Por lo que yo entendí, que tampoco soy ningún experto, es una estrategia comercial que utilizan grandes empresas cuando su negocio está perdiendo. Estas empresas implantan esta estrategia para sembrar el FUD.

 

¡¡Despierta!!

Bueno, bueno...como colofón final (disculpen el pleonasmo) Alfonso Gutiérrez hizo un llamamiento, quizás poco ortodoxo pero muy valiente debo añadir, a la motivación en esta época de crisis. A salir de esta prisión que es el miedo y sus barreras mentales. A luchar contra toda la información negativa actual que nos acecha. A no ser víctimas del pesimismo colectivo.   Una frase: Sé tú mismo, todos los demás ya están cogidos, Oscar Wilde. Un mensaje: ¡¡Despierta y sigue soñando!!

 

Resumiendo

Un evento dinámico, entretenido, ágil, con energía transmisora, que no deja indiferente y del que me llevo cosas aprendidas y otras a considerar. Pero como no podía ser de otra forma también hubo un par de charlas un poco peñazo. Fijaros que curioso, creo que fueron precisamente las presentaciones que se excedieron de los 12 o 15 minutos.

Objetos en JavaScript

9. November 2011 19:51 by Oscar.SS in Desarrollo Web  //  Tags:   //   Comments (0)

Los desarrolladores que venimos de lenguajes OO podemos encontrarnos con algunos detalles desconcertantes a la hora de trabajar con objetos JavaScript, dado que estos objetos difieren bastante de los conceptos que estamos acostumbrados a tratar. En primer lugar vamos a dar una definición más o menos formal y después veremos algunos ejemplos que explicarán mejor esta definición.

"Los objetos de JavaScript son colecciones de propiedades cada una con un nombre y un valor. Este valor puede ser otro objeto, por lo tanto, podemos decir también que los objetos JavaScript son contenedores para otros objetos JavaScript".

 

Crear objetos

En JavaScript no disponemos del concepto de clases, como tal, que nos permitan crear un contenedor o firma para nuestros objetos. En JavaScript los objetos se crean dinámicamente bajo demanda. Veamos unos ejemplos.

//Creamos un objeto Cliente
var cliente = new Object();

//Le creamos dínamicamente sus propiedades y le asignamos valores
cliente.nombre "Pedro García";
cliente.direccion "Calle San Juan, 3, 5º B";
cliente.fechaNacimiento = new Date(1975323);
cliente.empleoActual "Soldador";

Como podemos observar, en primer lugar creamos una instancia de Object y a continuación creamos sus propiedades asignándoles un valor. El añadir propiedades a un objeto se puede hacer en cualquier punto de nuestro código siempre que lo necesitemos. Es decir, un objeto JavaScript no tiene un conjunto de propiedades y método predefinidos como si lo tienen gracias a las clases los lenguajes OO. Esta elasticidad es muy potente dándonos plena libertad sobre las características de nuestros objetos.

Mencionar también que no disponemos de un compilador que nos avise de errores por lo que es muy importante escribir bien el nombre de las propiedades. Por ejemplo, supongamos que en algún punto de nuestro código necesitamos cambiar el domicilio de nuestro cliente.

cliente.dirección "Plaza Castilla, 4, 12º Izq";

Fijaros bien en que el nombre de la propiedad ahora tiene un acento. Lo que hemos conseguido con este error es que se creen dos propiedades con valores diferentes en nuestro objeto Cliente, una propiedad "direccion" y otra propiedad "dirección". Esto nos puede volver locos cuando tratemos de recoger el valor de la propiedad y descubramos que no se ha cambiado y en su lugar se han creado dos propiedades parecidas...¡mucho cuidado!

 

Objetos como contenedores de otros objetos

Cuando dimos la definición de un objeto JavaScript dijimos que se comportaban como contenedores de otros objetos. ¿En el ejemplo anterior de nuestro Cliente esto no ha sido así?. Desde luego que si, realmente hemos creado un objeto Cliente que contiene 3 instancias de String y una instancia de Date. Quizás lo veamos más claro con un ejemplo de código.

//Creamos un objeto para almacenar los valores de la dirección de nuestro cliente
var direcClient = new Object();
direcClient.calle "Castillo de Candanchú";
direcClient.numero "23";
direcClient.piso "5º B";

//Creamos un nuevo cliente y le asignamos el objeto direcClient a la propiedad direccion
var cliente = new Object();
cliente.nombre "Sergio Rodriguez";
cliente.direccion direcClient;
cliente.fechaNacimiento = new Date(1975323);
cliente.empleoActual "Progamador de los buenos";

//Accedemos a los valores de la dirección
var suCalle cliente.direccion.calle;

De hecho, si realmente los objetos son colecciones, ¿que nos impide recorrer el objeto como si de un Array se tratara?. No nos lo impide nada en absoluto. Veamos.

            for (var item in cliente) {
                
alert("Propiedad: " + item + "\nValor: " + cliente[item]);
            
}

La variable item en cada iteración mantiene una referencia al nombre de cada propiedad del objeto. O dicho de otro modo, en cada iteración la variable almacena una cadena de texto con el nombre de la propiedad. Veamos un par de resultados de ejecutar el código anterior.

Creo que ahora queda más claro eso de que los objetos son colecciones de propiedades que contienen otros objetos. Es importante comentar dos aspectos de esta característica.

En primer lugar, el nivel de anidamiento de objetos no tiene límites, podremos anidar tantos objetos como necesitemos para representar nuestro modelo. Y en segundo lugar, comentar que las funciones de JavaScript también son objetos y por lo tanto también pueden estar contenidas dentro de las propiedades de otros objetos. Pero esto lo veremos más adelante con detenimiento.

 

Expresiones como nombres de propiedades

Hasta ahora hemos visto que los nombres de las propiedades de nuestros objetos JavaScript son identificadores normales y corrientes. ¿Pero qué sucede si necesitamos identificadores más complejos?. Como por ejemplo "Empleo Actual", o "empleo.Actual", o "El empleo de este cliente", etc.

En este caso podemos utilizar una expresión como una propiedad del objeto de la siguiente forma.
 
nombreObjeto[expresión] = valor de la propiedad;
 
Esto es muy útil cuando a priori no conocemos el nombre de la propiedad, por ejemplo porque será suministrado por el usuario en un campo de texto. Veamos un ejemplo.
 
//Definimos unas cadenas que representarán nuestros nombres de propiedades
var nombrePropiedad "Empleo" "actual" "del" "cliente!!";

function 
GetNombrePropiedad() {
    
return "Nombre del cliente";
}

//Creamos la propiedades en el objeto y le asignamos valores.
var cliente = new Object();
cliente[GetNombrePropiedad()] "Raquel Gutierrez";
cliente[nombrePropiedad] "Doctora";

//Desde otro código accedemos a los valores de las propiedades
var nombreCliente cliente[GetNombrePropiedad()];
var 
empleoCliente cliente[nombrePropiedad];

 

Notación JSON para definir objetos

La sintaxis que hemos utilizado hasta ahora para definir objetos y asignar valores a las propiedades es muy familiar para los programadores de cualquiera de los lenguajes de la familia .NET y especialmente para los de C#. Pero JavaScript va mucho más allá y nos permite definir objetos con la sintaxis JSON a modo de literales de objetos.

var cliente =
    
{
        nombre: 
"Nuria Perez",
        fechaNacimiento: 
new Date(19731213),
        empleoActual: 
"Ingeniera",
        direccion: 
            {
                calle: 
"San Pascual",
                numero: 
23,
                piso: 
"3 C"
            
}
    }
;

 Esta es una forma mucho más compacta de escribir y definir código de objetos y desde luego también es más intuitiva sobre todo, si como en el ejemplo, tenemos objetos anidados.

 

El objeto window

El objeto window es el objeto más alto en la jerarquía del navegador, todos los demás objetos, ya sean nativos de JavaScript o creados por nosotros, cuelgan del objeto window, el cual será único para cada ventana o pestaña del navegador.

Cuando en JavaScript definimos una variable fuera del cuerpo de cualquier función, solemos decir que es una variable global. Pues bien, en realidad lo que estamos haciendo es crear una propiedad en el objeto window y asignarle un valor.

De hecho, a mí personalmente me gusta mucho más la notación que se aprecia en la imagen a la hora de recoger el valor de la variable o propiedad del objeto window. En funciones con muchas líneas de código, si hacemos referencia al objeto window, queda más claro que variables son de ámbito de la función y cuales son globales.

Por cierto, fijaros bien en el intellisense de la imagen anterior, en la declaración de la función sucede exactamente lo mismo. Lo que estamos haciendo en realidad al definir un método o función es asignárselo al objeto window. ¡Todo cuelga del objeto window!

 

Intellisense de JQuery en Visual Studio

2. October 2011 12:10 by Oscar.SS in Desarrollo Web, Herramientas  //  Tags: ,   //   Comments (2)

Con la llegada de JQuery a Visual Studio también llegó un archivo con la extensión vsdoc.js con toda la documentación necesaria para disfrutar de intellisense al escribir nuestro código cliente. Es algo muy sencillo, pero a veces estas cosas se pasan por alto.

 

Intellisense en páginas HTML

Si nos vemos en la obligación de escribir bloques de script en las propias páginas HTML, para disfrutar del intellisense de JQuery bastará con añadir una referencia al archivo de documentación con la extensión "vsdoc.js".

Como podemos apreciar en la imagen, al añadir la referencia al archivo mencionado, tenemos a nuestra disposición información sobre la función JQuery representada por el símbolo $.

Es importante mencionar dos aspectos. En primer lugar, cuando trabajemos en un proyecto ASP.NET MVC podemos vernos tentados de utilizar la siguiente sentencia.

<script src="@Url.Content("~/Scripts/jquery-1.5.1-vsdoc.js")" type="text/javascript"></script>

 Pero esto no funcionará dado que la referencia al archivo se realizará en tiempo de ejecución al tratarse de código de servidor.

Por otra parte es necesario mencionar que cuando despleguemos nuestra aplicación en producción debemos sustituir las referencias a los archivos de documentación por los archivos tradicionales, o incluso mejor aún, por las referencias a los archivos con la denominación "min.js".

 

Actualización 03/10/2010

Hablando esta mañana con mi compañero Omar Del Valle sobre este sencillo post, me comenta un pequeño truco que me ha parecido curioso e interesante para incluir aquí. Fijaros en la imagen siguiente.

En efecto, tenemos la referencia al archivo con la extensión "min.js" que como sabesmos es la que debería publicarse en el servidor de producción ya que al estar minimizada el tráfico de red generado es menor, tarda menos en cargar el script, etc.

Pero también tenemos una referencia, dentro de un if de servidor, al archivo de documentación "vsdoc.js". ¿Que conseguimos con esto?.

Por una parte, como se aprecia en la imagen, Visual Studio entiende la referencia al archivo de documentación y nos permite tener intellisense de JQuery. Y por otra parte, a la hora de publicar nuestra aplicación en producción, si se nos olvida eliminar en alguna página las referencias al archivo de documentación, gracias  al if(false), están nunca serán incrustadas en el HTML de vuelta al cliente.

Es necesario aclarar, que igualmente habría que eliminar esta linea de código al subir a producción, dado que el compilador tiene un pequeño trabajo extra, pero es cierto que en caso de olvido es un mal menor.

Por cierto, este truco también funciona con las páginas Web Forms y las etiquetas <%= %>.

 

Intellisense en archivos JS

Si nuestro archivo se encuentra en el mismo directorio que el archivo de documentación vsdoc.js, automáticamente tendremos a nuestra disposición las bondades del intellisense. Esto es así porque Visual Studio por defecto, ya sea una aplicación Web Form o MVC, buscará en la carpeta ~/Scripts el archivo de documentación y si lo encuentra creará por nosotros la referencia en nuestro archivo JS.

En el caso de que nuestro archivo JS se encuentre en otro directorio o anidado dentro de ~/Scripts, por ejemplo Scripts/Login/miArchivo.js, debemos crear nosotros la referencia de la siguiente forma.

/// <reference path="../jquery-1.5.1-vsdoc.js" />

Colocando esta linea de código al principio de nuestro archivo JS tendremos el intellisense disponible.

 

Intellisense en nuestras propias funciones

También podemos documentar nuestras funciones al igual que lo hacemos en nuestro código de servidor C#, VB o cualquier otro. Mirar el siguiente código.

Mencionar que las etiquetas summary, param y returns deben estar colocadas dentro del cuerpo del la función.

¡Espero que sea útil!

Estimación de las propias tareas

15. September 2011 22:51 by Oscar.SS in Gestión Proyectos, Personal  //  Tags: , ,   //   Comments (2)

Recuerdo en una ocasión, concretamente en el transcurso de una entrevista de trabajo, un empleador me preguntó si me veía en condiciones de estimar la duración de las tareas durante el ciclo de vida de un desarrollo.

Lo cierto es que la pregunta me desconcertó un poco, la entrevista era para un puesto de programador, y no me esperaba para nada una pregunta de este tipo. Quizás simplemente quería estudiar mi reacción ante una pregunta algo atípica para el puesto.

Yo respondí, con cierta seguridad (falsa seguridad), que me veía en condiciones de estimar con acierto mis propias tareas, pero quizás con menos exactitud las tareas ajenas a mi implicación directa...¡o algo así!

Mi interlocutor con cierto aire de condescendencia, me contestó que no me preocupara, que precisamente eso, el estimar las tareas de un proyecto y por ende la duración del mismo, es precisamente la tarea más complicada de esta profesión. 

Pues bien, sin darme cuenta mi respuesta no fué en absoluto acertada. Vengo observando desde hace algún tiempo que incluso realizar una estimación con exactitud de las propias tareas es mucho más difícil de lo que parece. Y supongo que esto no me sucede a mí solo....¡eso espero!  ;-)

Por un lado opino que este desacierto en la estimación de los pequeños módulos de un proyecto de los que en última instancia somos únicos responsables puede tener múltiples consecuencias negativas. Y por otro lado creo que esta habilidad, como todo en este mundo, se puede desarrollar siempre que pongamos el foco en ella y la practiquemos con los métodos que consideremos oportunos.

 

Algunas consecuencias negativas

En primer lugar me gustaría señalar el daño al amor propio. Parte de tu trabajo es códificar, analizar, implementar, desplegar, etc. Pero también lo es conocer que tiempo te puede llevar realizar cada una de estas tareas. No porque te lo pida un responsable de proyecto o un cliente, simplemente porque es parte de la forma en la que organizas tu trabajo e incluso hasta tu vida. De igual forma que te molestas (yo me cabreo) cuando un algoritmo no hace lo que tiene que hacer, o cuando se te ha olvidado comprobar una referencia nula, igualmente debes comprometerte con el hecho de conocer que partes de tu trabajo te lleva más o menos tiempo ejecutar.

Puedes perder la confianza de tu responsable de proyecto. Si continuamente le das estimaciones erróneas, se entiende que demasiado optimistas, este dejará de confiar en tu habilidad para determinar los tiempos de tu trabajo y comenzará a confiar en su habilidad que puede ser incluso peor que la tuya...¡esto lo haces tú en dos días!

Es un marketing nefasto para el trabajo realizado. Por muy bien que compile tu código (ni que unos compilaran mejor que otros), por muy bien documentado que esté tu código (aquí si), por muy perfecto que sea tu modelo de datos, etc y etc...Si le prometiste 3 días y se lo entregas en 5, será este hecho el que se grabará en su cabeza (y posiblemente en la del cliente) no teniendo importancia alguna el resto de tu fantástico trabajo.

Puede suponer una carga adicional de trabajo para tus compañeros. Al crear esta desconfianza es posible que otro compañero tenga que ayudarte o darte pequeños empujones (con el tiempo collejas) y como consecuencia te toque pagar las "cañitas en el after work".

 

¿Como desarrollar esta habilidad?

Aquí es cuando yo me tiro a la piscina y comparto con vosotros algo que se me ha ocurrido y que por lo tanto tiene la validez de...permitirme la expresión...¡un billete de 1 euro con la cara de Franco!

En primer lugar, como he comentado al principio, debemos poner el foco en el problema. Empezar a concienciarnos de su importancia y tomar pequeñas medidas, siempre que las circunstancias lo permitan, para poco a poco perfeccionar esta habilidad.

Una posible actuación podría ser confeccionar un registro de las distintas tareas que llevamos a cabo durante los proyectos. 

Este registro nos permitiría conocernos un poco mejor en dos aspectos distintos. Por un lado que tipos de tareas nos llevan más tiempo realizar, y por otro, cuales son las tareas en las que más nos equivocamos a la hora de estimar su duración.

Soy consciente que este trabajo adicional solo es posible en ciertas circunstancias, dependiendo siempre del estado actual del proyecto, de la presión, etc. Pero creo que podría ser muy provechoso conocerse y poco a poco poder ofrecer una estimación más exacta.

Es más, me voy a envalentonar, y digo que debería estar incluido (si no lo está ya) en la definición de Work Items del TFS y poder aprovechar mediante minería de datos esta información. Por cierto, para todos aquellos que hacéis uso de la Técnica Pomodoro, quizás se podría medir la estimación en pomodoros.

Es cierto que no es una ciencia exacta, la misma tarea en distintos proyectos no tienen porque tener la misma duración, pero no deja de ser un intento o acercamiento al problema y sobre todo a conocernos un poco mejor en una faceta, creo yo, descuidada por muchos de nosotros como profesionales.

En fin, espero vuestros comentarios...¡portaros bien!  ;-)

Recent Comments

Comment RSS

Month List