Test de Carga: Web Performance Test con Visual Studio 2010

por Diego Rosso  22. diciembre 2011

 

Pequeña introducción

Continuando con el post anterior vamos a mostrar cómo podemos realizar pruebas de carga sobre nuestras aplicaciones web utilizando Visual Studio 2010 en forma más detallada. La idea principal es ver cómo responde nuestra web ante varias peticiones concurrentes y obtener información sobre los Performance Counters de nuestros servidores que nos servirán de base para detectar problemas en la aplicación o en los servidores donde está alojada.

Que son los Performance Counters?

Los contadores de rendimiento son objetos del sistema operativo que nos muestran información sobre el rendimiento del hardware y software, como por ejemplo la memoria, el disco y los procesos.

Un contador es una medida de un parámetro determinado. Estos se organizan en grupos como por ejemplo los que vienen con el sistema operativo que están comprendidos dentro del objeto System y otros que se instalan como los de SQL Server.

Windows trae una herramienta para acceder a los objetos y sus contadores, la misma se llama Performance Monitor, la cual podemos accederla yendo a Incio --> Ejecutar --> y escribir Perfom.

 

 

LoadTest1

 

WebTests

Para realizar nuestras pruebas de stress lo primero que debemos hacer es crear nuestros Webtest, en el cual se definen cuáles son las urls sobre las que van a realizarse las pruebas. Algo muy importante es que deben tener instalada la versión Ultimate del Visual Studio 2010 para poder contar con estos tipos de test (la versión 2008 del Visual Studio ya contaba con esta funcionalidad).

Pasos para crearlo.

1. En el visual Studio vamos a crear un nuevo proyecto del tipo Test, para eso ir a New –> Proyect  --> Test --> Test project y generamos el proyecto base de test.

 

LoadTest2

 

2. Eliminamos la clase que nos agrega por default.

 

LoadTest3

 

3. Agregamos un nuevo test del tipo Web Performance Test, haciendo botón derecho sobre el proyecto –> Add --> Web Performance Test

 

LoadTest4

Al hacer esto se nos abrirá el Web Test Recorder, donde debemos ingresar la dirección web que deseamos testear, en nuestro ejemplo ingresaremos www.google.com.ar y vamos a buscar VEMN y veremos como el Recorder va guardando las urls junto con sus parámetros gets, los cuales están dentro de una carpeta llamada QueryStrings Parameters.

 

LoadTest5

Luego cerraremos esta ventana y vamos a quedarnos a nivel de ejemplo con solo la primer URL y sus parámetros.

 

LoadTest6

 

 

 

Ahora debemos agregar a nuestro proyecto un Load test (test de carga) que será el encargado de simular múltiples peticiones sobre la URL que cargamos en el Webtest. Para esto hacemos botón derecho sobre el proyecto y seleccionamos add-->Load Test y se nos abrirá un wizard con su clásica ventana de bienvenida le damos next para para a configurar el test de carga.

 

LoadTest7

 

Lo primero que nos pide es un nombre para el escenario de test que vamos a crear y nos pide seleccionar que tipo de pausas queremos entre la ejecución de las distintas iteraciones, en el ejemplo lo dejaremos como viene por default y le pasaremos al próximo paso.

 

LoadTest8

En este caso nos pide que seleccionemos el patrón de carga el cual puede ser constante donde le definimos la cantidad de usuarios que debe simular de forma constante durante el transcurso de toda la prueba, o incremental que es el que vamos a elegir nosotros para nuestro ejemplo, los parámetros que nos pide son los siguientes

  • · Start User Count: Cantidad de usuarios que se generaran cuando comience la prueba, en nuestro caso pondremos 20.
  • · Step Duration:  Donde definimos la cantidad de segundos que van a pasar hasta que se agreguen más peticiones sobre la URL que estamos testeando, en nuestro caso 15 segundos.
  • · Step User Count:  Cantidad de usuarios que se agregaran una vez transcurrido el tiempo configurado en Step Duration.
  • · Maximun User Count: Donde definimos la cantidad máxima de usuarios a simular.

 

LoadTest9

 

Luego nos pide el modelo a utilizar por el test de carga, en nuestro caso elegiremos el primer modelo basado a partir del número total de pruebas. Podemos ver aquí un detalle de cada uno de estos modelos.

 

 

LoadTest10

 

En el próximo paso del asistente debemos elegir los webtest que deseamos testear en el presente escenario, en nuestro caso vamos a elegir el único que tenemos pero podríamos seleccionar varios y asignar la distribución para cada uno de estos.

 

LoadTest11

Ahora ingresamos las distintas formas de conexión que deseamos testear y la distribución que queremos darle a cada uno.

 

LoadTest12

 

En el próximo paso seleccionaremos los distintos browsers que queremos que el test de carga simule y la forma en que se distribuirá la carga.

 

LoadTest13

 

Ahora debemos ingresar el nombre del equipo que deseamos supervisar que debería ser donde se encuentra alojado el sitio web que estamos probando, este debe ser un servidor el cual se encuentre en nuestra red o nuestra propia máquina. Si nuestro sitio tiene distintos servidores como por ejemplo uno para la BD y otro para donde se encuentra alojado el sitio, podemos agregar ambos haciendo click en add computer.

Debemos seleccionar los performance counter que deseamos monitorear en cada uno de los equipos.

 

 

 

LoadTest14

En el último paso del Wizard, nos pide la duración del test que en nuestro caso lo vamos a dejar en 10 minutos y también podemos configurar si queremos que nos genere un log cada vez que un test falle, entre otras cosas.

Presionamos sobre Finish y podemos ver como quedo configurado nuestro test de carga.

 

LoadTest15

 

Listo! Estamos en condiciones de poner a correr nuestro test y ver el comportamiento de los performance counters de los diferentes equipos supervisados.

 

LoadTest16

 

En nuestro próximo post vamos a ver cómo generar el código de nuestros Webtest para hacerlos más dinámicos y como pasar parámetros a la URL a través de distintas fuentes como pueden ser base de datos, archivos csv o xmls.

Tags:

.NET | Desarrollo Web | Testing | Visual Studio

Run Web Camp en Córdoba

por Alejandra Federico  5. mayo 2011

El lunes 16 de Mayo estará participando Daniel Laco (MVP) junto a Eugenio Serrano (MVP) y Enrique Dutra (MVP) en una de las conferencias sobre web que realiza Microsoft, con el impulso del MUG y con el apoyo del Departamento de Ingeniería de Sistemas de UTN Facultad Regional Córdoba.

Lugar: Aula Magna UTN, Maestro M. Lopez esq. Cruz Roja Argentina Ciudad Universitaria - Córdoba Capital. 

Horario: 17:00 a 22.00 Hs.

Agenda: 

17:00 Acreditación.
17:30 Apertura del evento, presentación de los oradores, explicación del contenido de software que se entregará a los asistentes.
17:40 Acceso a Datos y Modelado con Entity Framework (Daniel Laco)
19:00 Intervalo.
19:20

Seguridad en la nube. Gestión con BRS Datacenter. Demos con máquinas virtuales (Enrique Dutra)

20:40 ASP.Net MVC. Un cambio de vista en MVC: Razor Syntax. Aplicaciones Ajax con MVC  (Eugenio Serrano)
22.00 Cierre

Más información AQUÍ

Registración AQUÍ

Tags:

ASP.NET | Desarrollo Web | Entity Framework

Run Web Camp en Buenos Aires

por Daniel Laco  1. marzo 2011

El 15 de Marzo estaré participando junto a Martin Salías como orador en una de las conferencias del evento sobre web que organiza Microsoft.

En esta oportunidad estaremos hablando de Acceso a Datos y Modelado con Entity Framework, siempre dentro del ambiente de ASP.NET MVC.

En http://www.microsoft.com/argentina/run/ pueden encontrar toda la agenda y el link de registración.

Es una jornada muy interesante porque contaremos con la visita de Phil Haack, Program Manager de ASP.NET

Tags: ,

ASP.NET | Desarrollo Web | Entity Framework

Seguridad y Autorizacion centralizada en base de datos con Asp.Net MVC

por Andres Stang  22. diciembre 2010

La palabra Seguridad es siempre una consulta que recibo cuando hablo de cómo programar en Asp.Net, y siempre me gusta dar el mismo chiste como respuesta: “Vamos por partes decía Jack el Destripador”. Es importante dividir un problema grande en problemas más pequeños y por ende más manejables, y hablando de seguridad la fórmula es sencilla.

 

SEGURIDAD = AUTENTICACIÓN + AUTORIZACIÓN


Es decir, tenes que resolver por un lado como identificar al usuario, para saber que es quien dice ser que es, y por el otro lado una vez que sepamos su identidad, tenemos que decidir si lo dejamos acceder o no.

Cuando creamos un proyecto nuevo de MVC, el template nos da una GRAN ayuda y propone resolver (mejor dicho, ya lo implementa y lo resuelve por defecto) cada tema con un componente específico. Para la autenticación utiliza Asp.Net Membership y para la autorización el decorador [Authorize].

Ambos componentes funcionan maravillosamente pero hay uno que me gusta y otro que no. Concretamente Asp.Net Membership me parece perfecto para resolver una gran cantidad de escenarios y contextos, y generalmente lo utilizo en mis proyectos. Pero el decorador de autorización a mi criterio tiene dos grandes falencias:

  • Falta de flexibilidad: el componente de autorización puede recibir como parámetro el usuario y el rol, pero esto queda explícito en el código, es decir, si me surge la necesidad de agregar un nuevo rol al sistema deberé recorrer el código, cambiarlo, recompilar y realizar un deploy del sitio.
  • Verborragico: el componente requiere gran escritura y definición por parte del programador. Esto, mas allá de la poca elegancia del código, define que sea el programador quien decide quien esté autorizado a entrar a cada acción. Y ante un error, descuido o falta de memoria del programador podemos comprometer a nuestra aplicación dejando expuesta funcionalidad sensible a usuarios indeseados.

 

¿Cómo resolvemos esto?


Allá por el año 2007 Daniel Laco escribió uno de los post más consultados de este sitio:


Autenticación de usuarios basada en Roles utilizando HTTPModules en ASP.NET


De forma muy sencilla y elegante resuelve las dos falencias presentadas. Y si bien el código no es compatible con todas las versiones del .net framework, o con el paradigma MVC, el concepto si aplica en el universo Asp.net.

Lo que haremos el día de hoy, es actualizar un poco el código para que puede ser utilizado en nuestros proyectos de MVC ;)

Lo primero que tenemos que hacer es programar el método de nuestro modulo, quedaría algo así:

 

 public void Init(HttpApplication context)
 {
     context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
 }
 
 void OnAuthorizeRequest(object sender, EventArgs e)
 {
     HttpContext context = ((HttpApplication)sender).Context;
 
     RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
 
     if (routeData != null)
     {
         string controller = routeData.GetRequiredString("controller");
         string action = routeData.GetRequiredString("action");
 
         if (!EstaAutorizado(controller, action, context.User))
         {
             /// 401 es el codigo de resultado HTTP para acceso no autorizado
             context.Response.StatusCode = 401; 
             context.Response.End();
         }
     }
 }

 

En el código vemos cómo recuperar la información de la ruta para saber que método estamos ejecutando, y luego definir que si no se encuentra autorizado el usuario, le responderemos con un código HTTP estándar: 401 (lista de códigos)

De esta forma dejamos actuar al framework de asp.net que ya tiene resuelto el enganche y resolución del caso. Por ejemplo, MVC viene configurado por defecto que ante un error de autenticación redirija al usuario automáticamente a la página de login:

 

<authentication mode="Forms">
   <forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>

 

Lo único que nos falta, es recordar agregar el modulo a nuestro web.config para que se ejecute:

<httpModules>
  <add name="MiModulo" type="AutorizacionMVCHttpModule.Models.MiModulo"/>
</httpModules>

 

Listo! Con muy pocas líneas hemos resuelto de manera elegante y limpia un requerimiento esencial y controversial en la mayoría de nuestros proyectos.

Les dejo el código fuente de ejemplo para que lo puedan descargar y ver implementado
Download AutorizacionMVCHttpModule.zip (262,77 kb)

Happy coding!

Tags: , , , , ,

.NET | ASP.NET | Desarrollo Web

Enviando JSON a una acción en ASP.NET MVC

por fernando  22. abril 2010

 

Descargar Código Fuente

El otro día estaba intentando enviar datos a una acción utilizando el AJAX de jQuery. En la mayoría de los casos, podrán utilizar este método y enviar datos a una acción sin problemas, ya que el default binder de MVC se encarga de interpretar los datos.

Mi problema surgió cuando intenté enviar datos más complejos. En el controlador tenía el siguiente método:

   1:          [AcceptVerbs(HttpVerbs.Post)]
   2:          public virtual JsonResult Actualizar(Producto producto)
   3:          {
   4:              //HACER ALGO 
   5:          }

Este método sólo acepta un POST, y tiene un argumento de tipo Producto. Veamos cómo está compuesta esta clase:

   1:      public class Producto
   2:      {
   3:          public int Id { get; set; }
   4:          public string Nombre { get; set; }
   5:          public IEnumerable<Promocion> Promociones { get; set; }
   6:   
   7:          public class Promocion
   8:          {
   9:              public string Id { get; set; }
  10:              public double Descuento { get; set; }
  11:              public DateTime FechaDesde { get; set; }
  12:              public DateTime FechaHasta { get; set; }
  13:          }
  14:      }

 

Para poder enviar esto utilizando jQuery y AJAX, lo más sencillo sería hacer:

   1:      var data = {
   2:          "Id": 1,
   3:          "Nombre": "Cualquier Nombre",
   4:          "Promociones": [
   5:         {
   6:             "Id": 1,
   7:             "Descuento": 0.15,
   8:             "FechaDesde": new Date(año, mes, día),
   9:             "FechaHasta": new Date(año, mes, día)
  10:         },
  11:         {
  12:             "Id": 2,
  13:             "Descuento": 0.05,
  14:             "FechaDesde": new Date(año, mes, día),
  15:             "FechaHasta": new Date(año, mes, día)
  16:         }
  17:       ]
  18:      };
  19:   
  20:      $.ajax({
  21:          type: "POST",
  22:          dataType: "json", // Tipo de dato que devuelve el server
  23:          url: 'Controller/Action',
  24:          data: data, // Datos a enviar
  25:          success: function(serverResponse) {
  26:              // Realizar algo cuando la llamada es exitosa
  27:          },
  28:          error: function() {
  29:              // Realizar algo cuando la llamada falla
  30:          }
  31:      });
 

Lo que estoy haciendo es crear un objeto con los miembro Id, Nombre y Promociones y asignándolo a la variable data.

Sin embargo, el miembro Promociones es un objeto de tipo Array. Por default, la función $.ajax() intentará convertir cualquier dato a un string. Como Promociones es un array, al intentar convertirlo a un string, terminará enviando al servidor lo siguiente:

IDDivision=6&IDBonificacion=LB6&Tipo=A&Vigencias=[object+Object]&Vigencias=[object+Object]

Es decir, jQuery serializa los valores de un mismo array con el mismo Key. Por ejemplo, {foo:["bar1", "bar2"]} se convierte en '&foo=bar1&foo=bar2'.

Sin embargo, como el valor de cada elemento de Promociones es otro objeto, lo que termina enviando es el .toString() del objeto, el cual es "[object Object]" justamente. El Default Model Binder de ASP.NET MVC, intentará hacer el bind al objeto Producto, pero debido a que jQuery serializo incorrectamente el objeto, el miembro Promociones terminará siendo null, en lugar de los datos que estábamos intentando enviar realmente.

Para resolver este problema, podemos convertir los objetos javascript a JSON. Para hacer esto, utilicé JSON for jQuery (link), pero se puede utilizar cualquier cosa que tome un objeto javascript y lo transforme a JSON. Al enviar los datos al server, debemos asegurarnos que el content type sea del tipo application/json, que es lo que estoy haciendo en la línea 5 del siguiente código:

 

   1:      var jsonString = $.toJSON(data);
   2:      $.ajax({
   3:          type: "POST",
   4:          dataType: "json", // Tipo de dato que devuelve el server
   5:          contentType: 'application/json', // Tipo de datos que envío
   6:          url: 'Controller/Action',
   7:          data: jsonString, // Datos a enviar
   8:          success: function(serverResponse) {
   9:              // Realizar algo cuando la llamada es exitosa
  10:          },
  11:          error: function() {
  12:              // Realizar algo cuando la llamada falla
  13:          }
  14:      });

Fíjense que antes de hacer la llamada a ajax(), estoy transformando la variable data a JSON, y pasando su resultado a la función $.ajax(), en lugar del objeto. La variable jsonString entonces quedará en:

'{"Id": 1, "Nombre": "Cualquier Nombre", "Promociones": [{ "Id": 1, "Descuento": 0.15, "FechaDesde": "2010-01-01T03:00:00.000Z", "FechaHasta": "2010-05-31T03:00:00.000Z" }, { "Id": 2, "Descuento": 0.05, "FechaDesde": "2010-06-02T03:00:00.000Z", "FechaHasta": "2010-08-01T03:00:00.000Z" } ] }'

Si prestan atención, podrán darse cuenta que el JSON string es exactamente igual que la declaración de la variable data, definida más arriba. La única diferencia es que jsonString es literalmente un string, y data es un objeto javascript.

Ahora, lo único que queda resolver es el Model Binding del lado del servidor. Lamentablemente, ASP.NET MVC 2 no interpreta JSON correctamente, por lo tanto vamos a tener que hacer algo para hacerlo funcionar.

El enfoque más común sería hacer un Custom Model Binder. Sin embargo, esto implica que en cada acción que recibe JSON, debemos indicar explícitamente a MVC que utilice nuestro Model Binder. Si se trata de una sola acción, no habría ningún problema, pero si hay muchas acciones que utilizan el Model Binder, y todas reciben distintos tipos de datos, se va a volver muy tediosa la implementación.

Por suerte, en MVC 2, tenemos algo llamado Value Providers. Mientras que los Model Binders son utilizados para bindear datos que recibe el servidor, Value Providers proveen una abstracción para los datos en sí.

Para resolver mi problema, creé un Custom Value Provider que recibe datos JSON y lo serializa a un diccionario, en lugar de al objeto. Luego, éste diccionario es pasado al Default Model Binder de MVC, el cual realiza el bind al objeto final, e incluso realiza cualquier validación que ustedes hayan indicado.

El Custom Value Provider es el siguiente:

   1:  public class JsonValueProviderFactory : ValueProviderFactory
   2:  {
   3:      public override IValueProvider GetValueProvider
   4:                                           (ControllerContext controllerContext)
   5:      {
   6:          object jsonData = GetDeserializedJson(controllerContext);
   7:   
   8:          if (jsonData == null)
   9:              return null;
  10:   
  11:          var dictionary = new Dictionary<string, object>
  12:                                             (StringComparer.OrdinalIgnoreCase);
  13:   
  14:          FlattenToDictionary(dictionary, string.Empty, jsonData);
  15:   
  16:          return new DictionaryValueProvider<object>
  17:                                       (dictionary, CultureInfo.CurrentCulture);
  18:      }
  19:   
  20:      private static object GetDeserializedJson
  21:                                           (ControllerContext controllerContext)
  22:      {
  23:          if (!controllerContext.HttpContext.Request.ContentType
  24:            .StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
  25:              return null;
  26:   
  27:          string bodyText = new StreamReader
  28:                (controllerContext.HttpContext.Request.InputStream).ReadToEnd();
  29:   
  30:          if (string.IsNullOrEmpty(bodyText))
  31:              return null;
  32:   
  33:          var serializer = new JavaScriptSerializer();
  34:   
  35:          return serializer.DeserializeObject(bodyText); 
  36:      }
  37:   
  38:      private static void FlattenToDictionary(
  39:            IDictionary<string, object> dictionary, string prefix, object value)
  40:      {
  41:          var dictionaryValue = value as IDictionary<string, object>;
  42:   
  43:          if (dictionaryValue != null)
  44:          {
  45:              foreach (KeyValuePair<string, object> entry in dictionaryValue)
  46:              {
  47:                  string propertyKey;
  48:   
  49:                  if (!string.IsNullOrEmpty(prefix))
  50:                      propertyKey = prefix + "." + entry.Key;
  51:                  else
  52:                      propertyKey = entry.Key;
  53:   
  54:                  FlattenToDictionary(dictionary, propertyKey, entry.Value);
  55:              }
  56:          }
  57:          else
  58:          {
  59:              var listValue = value as IList;
  60:              if (listValue != null)
  61:              {
  62:                  for (int i = 0; i < listValue.Count; i++)
  63:                      FlattenToDictionary(dictionary,
  64:                                          prefix + "[" + i + "]", listValue[i]);
  65:              }
  66:              else
  67:                  dictionary[prefix] = value;
  68:          }
  69:      }
  70:  }

Y luego, debemos agregar la siguiente línea en el Global.ajax de nuestra aplicación:

   1:  protected void Application_Start()
   2:  {
   3:          RegisterRoutes(RouteTable.Routes);
   4:          ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
   5:  }

Listo! Ahora al enviar JSON al servidor, nuestro Value Provider interceptará el request, y serializará los datos de tipo JSON a un diccionario que pueda ser interpretado por el Default Model Binder. Lo único que debemos recordar hacer es setear el ContentType a 'application/json', y éstos requests serán procesados por nuestro Value Provider.

Ahora, veamos un poco qué está haciendo el Value Provider.
Al único método que tenemos que hacerle override de la clase ValueProviderFactory es a GetValueProvider(). Lo que hace es deserializar JSON y transformarlo en un objeto .NET, luego lo serializa al diccionario y devuelve un DictionaryValueProvider, el cual es utilizado más tarde por el default model binder.

El método GetDeserializedJson() hace exactamente lo que dice, deserializa JSON. Hay que tener cuidado de pasarle un string que contenga JSON, porque puede arrojar una excepción si se pasa JSON invalido. Probablemente sería conveniente encerrar a la llamada DeserializeObject en un try/catch, y devolver null cuando falle.

Finalmente, el método FlattenToDictionary() es un método recursivo que recorre el objeto deserializado, que para este ejemplo es el siguiente:

clip_image002

Como verán, el objeto deserializado es un Dictionary<string, object>. Para Id y Nombre, el tipo de dato de Value es int y string respectivamente. Para Promociones, en cambio, es un Array de object, y cada elemento de ese Array es un Dictionary<string,object>. Lo que hace FlattenToDictionary() es recorrer todos estos elementos para 'aplanarlo' (flatten) a un diccionario. El método nos devuelve esto:

clip_image004

Si leyeron el post de Andres Stang probablemente esto les resulte familiar. Lo que hace el método es recorrer el objeto, y construir el Key de cada uno de los valores que contiene para poder insertarlo en un diccionario, donde todos los valores de cada elemento sea un tipo de dato primitivo. Este diccionario luego es interpretado por el default model binder. Es decir, lo que estamos haciendo es transformar JSON a un formato que pueda ser interpretado por el default model binder.

Les dejo el código fuente con una aplicación de ejemplo para que prueben:

JsonToMVCAction.rar (153,28 kb)

Tags: , , ,

.NET | ASP.NET | Desarrollo Web | JQuery

Formulario Cabecera-Detalle en Asp.Net MVC con el default ModelBinder

por Andres Stang  30. marzo 2010

 

Descargar Codigo Fuente

Tal vez les suceda que alguna vez en su feliz programación de Asp.Net MVC quieren generar un formulario de entrada de datos que permita, sin los molestos tiempos de carga de postback, agregar N cantidad de elementos.

Es decir, generar un modelo de Cabecera-Detalle en el cliente, y luego poder leerlo del lado servidor utilizando solo MVC y Javascript. No, me refiero a SOLO MVC, es decir sin un ModelBinder personalizado, que sería la opción que primero nos viene a la mente gracias a la extensibilidad propuesta por el framework.

Podemos imaginarnos el siguiente ejemplo de modelo:

   1: public class Materia
   2: {
   3:     public int Codigo { get; set; }
   4:     
   5:     public string Nombre { get; set; }
   6:  
   7:     public List<Alumno> AlumnosInscriptos { get; set; }
   8: }

Supongamos que queremos permitir al usuario generar una nueva materia y asignarle alumnos a la misma desde una lista de selección. Para simplificar el alumno va a estar definido por:

   1: public class Alumno
   2: {
   3:     public int Matricula { get; set; }
   4:  
   5:     public string Nombre { get; set; }
   6: }

 

Entonces realizamos el siguiente formulario web:

 

En el mismo vamos a poder cargar las propiedades de la materia y mediante javascript permitiremos que se agreguen los alumnos al seleccionarlos del combo al presionar “Agregar”.

Pero… como hacemos luego para leer las propiedades de la materia y los N alumnos seleccionados del lado del servidor?

Muy fácil, utilizando el ModelBinder por defecto de MVC. Es decir, el framework ya viene preparado para este escenario, solo que (a mi apreciación) está poco documentado.

Es decir, en nuestro método de controlador solo tendremos que colocar la siguiente definición:

   1: [AcceptVerbs(HttpVerbs.Post)]
   2: public ActionResult Index(Materia nuevaMateria)
   3: {
   4:     // HACER ALGO CON LA NUEVA MATERIA
   5:  
   6:     ViewData["CantidadAlumnos"] = nuevaMateria.AlumnosInscriptos.Count;
   7:  
   8:     return View("Alumnos");
   9: }

Y automáticamente podemos leer la instancia de la clase Materia con sus alumnos relacionados.

Donde está el secreto???

Lo importante es que al generar las filas dinámicamente de la tabla de alumnos también generemos los inputs para los valores de los alumnos que vayamos agregando. Por ejemplo, al agregar la fila nueva también insertaremos dos inputs ocultos de html con los valores que requiere la clase Alumno, es decir Matricula y Nombre:

   1: <input type="hidden" value="22" name="AlumnosInscriptos[1].Matricula" 
   2:     id="AlumnosInscriptos[1].Matricula" />
   3: <input type="hidden" value="Pedro" name="AlumnosInscriptos[1].Nombre" 
   4:     id="AlumnosInscriptos[1].Nombre" />

Podemos observar la particularidad del nombre y id del tag, es decir, debemos llamarlos de la siguiente manera:

<NombrePropiedadPadre>[indice].<NombrePropiedadHijo>

O para nuestro ejemplo:

AlumnosInscriptos[0].Nombre

De esta manera, el ModelBinder interpretara que se trata un elemento perteneciente a nuestra colección y nos facilitara el trabajo.

 

 

Pongo a disposición el código fuente perteneciente al ejemplo de este post:

ListBinder.zip (264,49 kb)

Happy Programming!

Tags: ,

ASP.NET | Desarrollo Web

22 Librerias para gráficos y diagramas en la web

por Daniel Laco  17. marzo 2010

Siguiendo con la idea de tener reunido en el blog, las direcciones de plugins y librerias para gráficos en la web.

Me encontré con esta excelente lista http://www.onextrapixel.com/2009/11/24/22-awesome-visualization-libraries-charts-and-diagrams/

Aquí hay librerias para JQuery, pero tambien hechas en Flash, etc.

 

Tags: , ,

ASP.NET | Desarrollo Web | Javascript | JQuery

La correcta elección de las KEYWORDS en SEO (Search Engine Optimization)

por Alejandra Federico  17. febrero 2010

A la hora de querer seleccionar cuáles son aquellas palabras claves que debemos utilizar, para que nuestro sitio web este posicionado entre los primeros en los resultados de una búsqueda, se nos hace realmente dificil.

Es por ello que aquí les dejo algunas herramientas que quizás les sirva de ayuda para la selección de las palabras claves:

  • http://www.keyworddiscovery.com/search.html Esta herramienta nos sirve permite descubrir las diferentes palabras que los usuarios están utilizando en los buscadores, relacionada con la palabra que escribimos
  • http://www.kwmap.net/  Es una herramienta gráfica que muestra las relaciones entre los término de búsqueda como un gráfico.
  • http://freekeywords.wordtracker.com/ Esta herramienta te dará una lista con al menos 100 palabras relacionada con las palabras que buscamos y, lo más importante es que lo hace en orden de importancia según la cantidad de veces buscada.
  • http://www.abakus-internet-marketing.de/tools/topword.htm Es una herramienta que analiza las palabras claves y frases de las palabras claves de un sitio. Nos puede servir para estudiar nuestro propio sitio.

 

Tags: , ,

ASP.NET | Desarrollo Web

Optimización de sitios webs con Sprites

por Daniel Laco  5. febrero 2010

Si bien es una técnica antigua, existe la posibilidad de utilizarla en páginas webs mediante el uso de CSS.

Esto nos permite reemplazar el uso de muchas imágenes en nuestro sitio, por una sola que contenga lo que necesitamos. Esto reduce mucho los request al sitio, con la consiguiente mejora en la carga de las páginas.

Aqui les dejo una recopilación de artículos (en Inglés) con explicaciones y ejemplos sencillos de está forma de pensar las páginas.

Creando fácilmente Sprites con CSS

http://cssglobe.com/post/3028/creating-easy-and-useful-css-sprites

Explicación de que son los Sprites

http://www.peachpit.com/articles/article.aspx?p=447210

El misterio de los Sprites de CSS, Tutoriales y Ejemplos

http://www.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/

 

Tags: ,

ASP.NET | Desarrollo Web | Sharepoint

9 puntos para lograr posicionarse (SEO)

por Alejandra Federico  30. enero 2010


9 puntos para lograr posicionarse (seo)

 

El SEO (Search Engine Optimizer) consiste en aplicar diversas técnicas que tienden a lograr que los buscadores de internet sitúen nuestra página en una buena posición y categoría alta, para determinados términos y frases claves.

A la hora de querer posicionarnos primeros debemos tener en cuenta los siguientes puntos:

  • Para empezar debemos focalizarnos en el título. Es lo más importante, primero porque los buscadores le dan bastante importancia a las palabras del título (sobre todo google) y luego porque es lo primero que se ve en la página de resultados. Hay que redactar un título que contenga las palabras claves en las que queramos estar bien posicionados y que sea atractivo al usuario que ve el resultado de la búsqueda. Debemos evitar colocar artículos (el, la, un, una). No se recomienda que sea superior a 60 caracteres, debe poseer aproximadamente entre 4 a 6 palabras. Los buscadores le dan mucha importancia a las palabras en negrita y de mayor tamaño.
  • Otro punto a tener en cuenta son las palabras claves. Para poder aparecer en los buscadores es necesario que nos focalicemos en aquellas palabras por las cuales creemos que nos van a buscar. Estas palabras claves deben ir en los títulos, etiquetas alt de las imágenes, los metatags, las URLS de nuestra página y en los enlaces de otras web.
    Se deben medir la densidad de las palabras claves. La densidad es el ratio de apariciones de una palabra o frase clave en el total de palabras que componen un texto. Por ejemplo, para un texto de 200 palabras, si una palabra aparece 10 veces, su densidad será del 5%.
    La densidad de palabras clave es uno de los factores que tienen en cuenta los buscadores para ordenar los resultados de una búsqueda.
    Para poder chequear como se encuentra nuestro sitio con respecto a la densidad existen algunos programas que nos indican cuales son las palabras más relevantes que figuran en nuestra web: 
  • Nuestro sitio debe poseer contenido de calidad de esta manera vamos a lograr que otras web nos enlacen. El blog nos puede servir de gran utilidad para que otros realicen visitas. Como mínimo hay que publicar un artículo por mes. Un modo para poder mantenerlo es obtener de otro sitio algún artículo interesante y copiar el link de donde fue sacado.
  • Los enlaces funcionan como una especie de voto o adhesión a una web en particular. Si los enlaces son de calidad esa valoración será positiva, de lo contrario nos perjudicarán.
  • En las etiquetas se debe utilizar H1 H2 H3… El H1 es recomendable que haya uno sólo por página, H2
    y H3 se pueden repetir algunas veces, aunque siempre ubicados de forma
    correcta:

    H1 para el título
    H2 para el título de las entradas
    H3 para los comentarios y otras subcategorías
  • No se debe insertar contenido importante en pdf, medios gráficos o flash. El abuso de JavaScript y Flash dificulta que un buscador nos "entienda".
  • Participar en redes sociales, por ejemplo Linkedin, Facebook, Hi5, Orkut, y de esta manera poder obtener mas visitas a nuestro sitio web.
  • Se debe realizar un mapa del sitio (site map). Si no se tiene es conveniente confeccionar un mapa del sitio actual, que contenga todas las URL’s de la páginas publicadas, incluyendo sus títulos, descripciones, palabras clave, meta tag robots, fecha de última modificación y nivel o algún tipo de clasificación de importancia dentro del árbol.
  • Puntos que no hay que realizar para NO ser penalizados por los buscadores:
    1. Evitar utilizar textos ocultos
    2. Evitar utilizar enlaces ocultos.
    3. No cargar la página con palabras claves irrelevantes.
    4. No enviar consultas automatizadas a google.
    5. Venta y/o compra de enlaces con el sólo motivo de aumentar artificialmente el PageRank.
    6. Técnicas de alto riesgo como el cloaking (mostrar dos o más páginas diferentes según quien desee visualizarla, es decir, no enviar la misma página al usuario y al buscador).
    7. Páginas Doorway (páginas creadas con el propósito de posicionarse para una determinada palabra clave y, entonces, ser una página de entrada a la web alternativa) creadas masivamente o de contenido prácticamente idéntico.
    8. Enlaces entrantes, es decir, hacia nuestra web, en cantidad masiva desde weblogs, guestbooks o granjas de enlaces.
    9. Enlaces salientes, es decir, desde nuestra web, hacia sitios web que realizan prácticas de alto riesgo o SPAM.
    10. No crear varias páginas, subdominios o dominios que presenten básicamente contenido duplicado.

Como conclusión, en el posicionamiento juegan cientos de variables y algorítmos que cambian día a día. Por más que en determinados
momentos se logren excelentes resultados, nadie tiene la verdad. No es una ciencia cierta.

Tags: , ,

ASP.NET | Desarrollo Web

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML