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 ;)

17 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!
lunes, 26 de abril de 2010
ASP.NET MVC Resulta algo paradójico que ASP.NET MVC sea capaz de generar código para comprobar tanto en cliente como en servidor que la longitud del texto introducido sea menor que la indicada con la anotación [StringLength], y sin embargo, los helpers habituales no generen el atributo maxlength en el tag <input type="text">.

Podemos comprobarlo muy fácilmente. Por ejemplo, dada una entidad del Modelo como la siguiente:

public class Persona
{
  [StringLength(20, ErrorMessage="Máximo {1} caracteres")]
  public string Nombre { get; set; }
}

Si creamos su vista de edición por defecto e introducimos en ella los validadores en cliente, obtendremos en tiempo de ejecución un resultado como el que podemos apreciar en la siguiente captura de pantalla:

image
Es decir, los validadores automáticos, tanto en cliente como en servidor, nos avisan de que hemos superado el número máximo de caracteres a introducir, pero no se impide que esto se produzca mediante el atributo maxlength de la etiqueta el tag <input type="text">.

Afortunadamente hay varias formas de solucionar este pequeño inconveniente, como creando nuevos helpers o utilizando plantillas de edición personalizadas. En este post veremos cómo implementar la primera opción, creando un helper que realice la tarea de forma automática.

Html.LimitedTextBoxFor()

Vale, sé que no es un nombre estupendo para el helper, pero de momento va a tener que valer con ese ;-P. La idea es que podamos generar text boxes que limiten el número de caracteres permitidos en función de lo indicado en las anotaciones del Modelo. Es decir, sobre el ejemplo anterior, ocurriría lo siguiente:

// En la vista:
<%= Html.LimitedTextBoxFor(model => model.Nombre ) %>
 
// HTML resultante:
<input id="Nombre" maxlength="20" name="Nombre" type="text" value="" />

El código del helper es el siguiente, y lo comento brevemente justo a continuación:

public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                this HtmlHelper<TModel> html, 
                Expression<Func<TModel, TProperty>> expression, 
                IDictionary<string, object> htmlAttributes)
{
  // Obtenemos los metadatos de la propiedad
  ModelMetadata metadata = 
         ModelMetadata.FromLambdaExpression(expression, html.ViewData);
 
  // Obtenemos la información utilizada para validar el tamaño del texto
  ControllerContext cctx = html.ViewContext.Controller.ControllerContext;
  StringLengthAttributeAdapter stringLengthValidator =
                    metadata.GetValidators(cctx)
                   .OfType<StringLengthAttributeAdapter>()
                   .FirstOrDefault();
 
  if (stringLengthValidator != null)
  {                                               // Si hay validación de este tipo...
    var parms = stringLengthValidator               
                     .GetClientValidationRules()     
                     .First()                        
                     .ValidationParameters;
                                                 // Obtenemos el valor del
    int maxlength = (int)parms["maximumLength"]; // tamaño máximo para el texto...
 
    if (htmlAttributes == null)
      htmlAttributes = new RouteValueDictionary();
 
    htmlAttributes.Add("maxlength", maxlength);  // y añadimos el atributo maxlength
  }
 
  return html.TextBoxFor(expression, htmlAttributes);
}

En primer lugar, estamos accediendo a los metadatos de la propiedad partiendo de la expresión lambda que recibimos como parámetro. Desde estos metadatos obtenemos, si existe, el validador asociado al atributo [StringLength], que es de tipo StringLengthAttributeAdapter.

Una vez obtenido el validador, buscamos en éste la información que será suministrada a los scripts en cliente, en particular el valor del parámetro “maximumLength”, introduciéndolo en la colección de atributos HTML que finalmente se envía al helper original asociando este valor al atributo maxlength de la etiqueta a generar.

Ahora, para simplificar las llamadas al helper desde las vistas, creamos un par de sobrecargas, similares a las que utilizamos normalmente en TextBoxFor():

public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                  this HtmlHelper<TModel> html, 
                  Expression<Func<TModel, TProperty>> expression, 
                  object htmlAttributes)
{
  return html.LimitedTextBoxFor<TModel, TProperty>(
           expression, 
           ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes))
  );
}
 
public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                  this HtmlHelper<TModel> html, 
                  Expression<Func<TModel, TProperty>> expression)
{
  return html.LimitedTextBoxFor(expression, null);
}

Y eso es todo. Si sustituimos en nuestras vistas las llamadas a TextBoxFor  por LimitedTextBoxFor tendremos la cuestión solucionada. Otra posibilidad, bastante más cómoda, sería retocar las plantillas de edición generadas por Visual Studio para que incluyan las llamadas a estos nuevos helpers.

Podéis encontrar el código fuente completo en Skydrive.

Publicado en: Variable not found.
Hey, ¿sabes que estoy en Twitter?
domingo, 25 de abril de 2010
Estos son los enlaces publicados en Variable not found en Facebook desde el lunes, 12 de abril de 2010 hasta el domingo, 25 de abril de 2010. Espero que os resulten interesantes :-)
Y no olvides que, si te interesa, 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, 21 de abril de 2010
¿Sómos los primeros en llegar al estadio? Casualmente encuentro en el post de Chris Eargle “Any() versus Count()” un tema del que pensaba escribir hace tiempo y al final dejé en el tintero: ¿cómo podemos determinar si una enumeración está vacía? Vale, es bien fácil, una enumeración está vacía si tiene cero elementos.

Si trabajamos con un array, podemos consultar la propiedad Length; si se trata de una colección, podemos utilizar la propiedad Count, que también nos devolverá el mismo dato de forma directa.

Sin embargo, cuando procesamos información es frecuente tratar con tipos de datos enumerables cuya implementación exacta desconocemos, y en los que no tenemos acceso a ninguna propiedad que nos permita conocer el número de elementos exactos que tiene almacenados. Por ejemplo, esto ocurre cuando obtenemos un conjunto de datos en forma de IEnumerable o trabajamos con LINQ sobre alguna fuente de información.

Pues bien, en estos casos hay que ser algo prudentes con la forma de consultar el número de elementos. Me he topado con código propio en el que, simplemente por despiste, utilizaba el método Count(), facilitado por LINQ para las enumeraciones y otras colecciones de datos, con objeto de saber si una lista estaba vacía:

var prods = services.GetProductsByCategory(category);
if (prods.Count() > 0)
{
   // Hacer algo con los elementos de la lista
}
else
{
   // No hay elementos
}

Seguro que ya os habréis percatado de que eso está mal, muy mal. El método Count() recorrerá uno por uno los elementos para contarlos, retornando el número exacto de ellos. En escenarios de un gran número de elementos, o cuando es costoso obtener cada elemento (como al traerlos de una base de datos) puede suponer un consumo de recursos enorme.

Y justo por esto existe el método Any(), que comprueba únicamente si existe al menos un elemento en la colección. Internamente este método itera sobre la colección retornando true cuando encuentra el primer elemento, por lo que es mucho más eficiente que el anterior:

var prods = services.GetProductsByCategory(category);
if (prods.Any()) // Mucho mejor :-)
{
  // Hacer algo con los elementos de la lista
}
else
{
  // No hay elementos
}

La utilización de Any() también es interesante para comprobar la existencia de elementos que cumplan una condición, expresada en forma de predicado; retornará true cuando encuentre el primer elemento que lo haga cierto:

if (pedidos.Any(p => p.Pendiente))
{
   // Mostrar alerta, hay al menos un pedido pendiente
}

Estamos en la puerta de un Estadio y queremos saber si vamos a ser los primeros en entrar al recinto… ¿le preguntaríamos al portero el número exacto de aficionados que ya están dentro para, si es cero, saber que somos los primeros? ¿O nos bastaría simplemente con preguntarle si hay alguien? ;-P

Publicado en: Variable not found
Hey: ¡estoy en Twitter!
lunes, 19 de abril de 2010
En la versión 1.0 de MVC, lo habitual era que los métodos helpers destinados a generar código de marcado retornaran un cadena de caracteres, como en el siguiente ejemplo:

public static class Helpers
{
  public static string Image(this HtmlHelper helper, string src, string alt)
  {
    TagBuilder tb = new TagBuilder("img");
    tb.Attributes["src"] = src;
    tb.Attributes["alt"] = alt;
    return tb.ToString(TagRenderMode.SelfClosing);
  } 
}

Que podía ser utilizado desde una vista de la siguiente forma, enviándolo al cliente con un bloque de salida directa de texto:

<%= Html.Image("/img/logo.gif", "Logo") %> 

Hasta aquí todo correcto. Ahora, ASP.NET 4 ha introducido un nuevo bloque de salida de texto capaz de codificar automáticamente en HTML, lo cual ayuda a evitar ataques relacionados con la inyección de scripts:

// Lo que antes (ASP.NET < 4) era...
<%= Html.Encode(Model.FirstName) %>
 
// En ASP.NET 4 es:
<%: Model.FirstName %>

El nuevo bloque de salida codificada es el método aconsejado para emitir contenido al cliente y se espera que los desarrolladores vayamos acostumbrándonos progresivamente a utilizarlo siempre, dejando a un lado al actual antiguo <%= %>.

Esto tiene un efecto lateral no deseado cuando estamos utilizando helpers que generen HTML. Por ejemplo, si emitimos la salida del helper anterior utilizando esta nueva técnica, observad el resultado que obtendremos:

// En la vista Index.aspx:
<%: Html.Image("/img/logo.gif", "Logo") %> 

image 
La solución a este problema se consigue utilizando como tipo de retorno del helper la nueva clase MvcHtmlString, introducida en ASP.NET MVC 2, que indica explícitamente a ASP.NET que no debe codificar la salida pues se trata de una cadena HTML controlada.

Así, modificando el código del helper de la siguiente forma, obtendremos el resultado esperado:

public static class Helpers
{
  public static MvcHtmlString Image(this HtmlHelper helper, string src, string alt)
  {
    TagBuilder tb = new TagBuilder("img");
    tb.Attributes["src"] = src;
    tb.Attributes["alt"] = alt;
    return MvcHtmlString.Create(tb.ToString(TagRenderMode.SelfClosing));
  } 
}

Todos los helpers del framework  MVC destinados a generar marcado retornan ahora, en la versión 2, este nuevo tipo de datos, y esto es lo mismo que deberíamos hacer con nuestros helpers personalizados. Además, gracias a unos curiosos malabarismos realizados en el interior de MvcHtmlString, nuestros helpers funcionarán tanto con ASP.NET 3.5 SP1 como con ASP.NET 4, tanto si utilizamos salida codificada como si no.

Publicado en: Variable not found.
Hey: ¡estoy en twitter!
domingo, 18 de abril de 2010
Estos son los enlaces publicados en Variable not found en Facebook desde el domingo, 11 de abril de 2010 hasta el domingo, 18 de abril de 2010. Como podréis comprobar, he modificado el formato, eliminando las imágenes y consiguiendo que sea más ligero.

Espero que os resulten interesantes :-)

Y no olvides que, si te interesa, 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, 14 de abril de 2010
CampusMVPHace un par de días, coincidiendo con el lanzamiento de Visual Studio 2010, se ha presentado oficialmente el curso de desarrollo de sistemas web con ASP.NET MVC 2 en el que he estado trabajando durante los últimos meses, y con el que me estreno como autor y tutor de CampusMVP, lo que supone para mí una auténtica satisfacción.

Ha sido un trabajo duro, no es una tarea sencilla estructurar y desarrollar contenidos de cierto volumen partiendo de cero, pero creo que el resultado ha valido la pena. El temario, salpicado con más de dos horas de vídeos demostrativos, ejemplos, y recursos adicionales, es el siguiente:
  • Introducción a ASP.NET MVC, donde realizamos un primer acercamiento al framework MVC, y sentamos las bases sobre las que continuar el aprendizaje.
  • En la  primera aplicación ASP.NET MVC crearemos nuestra primera aplicación partiendo de las plantillas por defecto de Visual Studio, que nos será de utilidad para comprender la estructura de este tipo de proyectos y el funcionamiento del marco de trabajo.
  • Continuaremos añadiendo funcionalidades a esta aplicación, donde introduciremos nuevas características partiendo desde cero, aprovechando la ocasión para profundizar en la creación de modelos, vistas y controladores.
  • Seguidamente estudiaremos la capa Modelo a fondo, viendo distintas formas de implementar sus componentes.
  • A continuación, nos sumergimos en la capa Controlador, detallando minuciosamente la creación de controladores, las posibilidades que nos ofrecen, y el conjunto de herramientas que nos facilita el framework para ellos, como el sistema de routing, el binding, filtros, o resultados de acciones.
  • También trataremos con gran detalle la creación de la capa Vista, donde describiremos sus tipos, implementación y mecanismos del marco de trabajo que nos facilitan la tarea, como los helpers, plantillas, o validadores, entre otros.
  • En Ajax con ASP.NET MVC realizaremos un recorrido por las distintas alternativas para la introducción de Ajax en nuestros sistemas, y mostraremos la solución a escenarios comunes.
  • También trataremos cómo organizar los proyectos en Áreas, y los cambios que implican en cuanto a la estructura y funcionamiento de las aplicaciones.
  • Y por último, dedicaremos un capítulo a temas adicionales, básicamente para tratar otros aspectos no incluidos en los módulos anteriores, como la realización de pruebas unitarias, internacionalización, o el despliegue de aplicaciones.
La duración estimada total del curso es de 8 semanas y se imparte online a través de la plataforma de formación de CampusMVP, a vuestro propio ritmo y con el horario que más os convenga. Y dado que soy tutor del curso, estaré a vuestra disposición para asistiros resolviendo las dudas o inquietudes que os pudieran surgir durante el proceso formativo.

Si estáis interesados, sólo tenéis que ir a la tienda online de CampusMVP y apuntaros directamente. Tened en cuenta que si trabajáis en España los cursos pueden salirle gratis a la empresa gracias a la formación bonificada.

¡Os espero! ;-)

Enlaces:
Publicado en: Variable not found.
domingo, 11 de abril de 2010
Como adelantaba en el post anterior, esta es la primera recopilación de los enlaces publicados en la página Variable not found en Facebook. Por ser la primera entrega, vamos a recoger los de las últimas semanas, desde el miércoles 24 de marzo de 2010 hasta el domingo 11 de abril de 2010.
Espero os resulten interesantes :-)

AntiXSS como codificador de salida por defecto en ASP.NET.AntiXSS como codificador de salida por defecto en ASP.NET.
Scott Guthrie recently wrote about the new syntax for HTML encoding output in ASP.NET 4. I also covered the topic of HTML encoding code nuggets in the past as well providing some insight into our design choices for the approach we took.
Fuente: haacked.com

Fecha: 09/04/2010
Stephen Walther habla sobre cómo mantener el historial del navegador en aplicaciones Ajax.Stephen Walther habla sobre cómo mantener el historial del navegador en aplicaciones Ajax.
One objection that people always raise against Ajax applications concerns browser history. Because an Ajax application updates its content by performing sneaky Ajax postbacks, the browser backwards and forwards buttons don’t work as you would normally expect.
Fuente: stephenwalther.com

Fecha: 09/04/2010
Creación de interfaces de introducción de datos con MVC 2.Creación de interfaces de introducción de datos con MVC 2.
The next part to this article series on MVC 2.0 is the user interface. We saw in the last article some basics on the changes of the user interface, which we'll delve into more in this article series. Here we will begin to look at how developers can construct the view user interface.
Fuente: dotnetslackers.com

Fecha: 09/04/2010
Novedades de VS 2010 relativas al soporte de Intellisense en javascript.Novedades de VS 2010 relativas al soporte de Intellisense en javascript.
ASP.NET, Visual Studio, ASP.NET 2.0, .NET
Fuente: weblogs.asp.net

Fecha: 09/04/2010
Interesante debate sobre la forma de gestionar el envío de passwords a la vista.Interesante debate sobre la forma de gestionar el envío de passwords a la vista.
Let's suppose you have a model like this: public class User { public string Username { get; set; } [DataType(DataType.Password)] public string Password { get; set; } } To test this out, you write an action: public ActionResult Index() {...
Fuente: bradwilson.typepad.com

Fecha: 08/04/2010
Proveedor LINQ para Twitter, en Codeplex.Proveedor LINQ para Twitter, en Codeplex.
LINQ to Twitter is a LINQ Provider for the Twitter micro-blogging service. It uses standard LINQ syntax for queries and includes method calls for changes via the Twitter API.ExampleYou can try LINQ to Twitter, even if you don't have a twitter account. ...
Fuente: linqtotwitter.codeplex.com

Fecha: 08/04/2010
¿Un ViewEngine para Balsamiq?¿Un ViewEngine para Balsamiq?
Invitation Message: A preview of the message appears below. A link and password (if necessary) is automatically appended to the message upon sending. A Screencast.com user has invited you to view content on Screencast.com:
Fuente: http://www.screencast.com/

Fecha: 08/04/2010
Serie de posts estudiando la propuesta de Áreas Portables del proyecto MvcContrib.Serie de posts estudiando la propuesta de Áreas Portables del proyecto MvcContrib.
Fuente: geekswithblogs.net

Fecha: 07/04/2010
Rutas editables moviendo el código de inicialización al global.asax.Rutas editables moviendo el código de inicialización al global.asax.
Introduction : Phil Haack's had written two great articles about Editable Routes, Editable Routes or Editable Routes Using App_Code.These Article are great. But if you not need to unit test your ...
Fuente: weblogs.asp.net

Fecha: 07/04/2010
Cómo renderizar una plantilla a un string en MVC 2. Por ejemplo, para componer mensajes de correo en formato HTML.Cómo renderizar una plantilla a un string en MVC 2. Por ejemplo, para componer mensajes de correo en formato HTML.
In one of the projects that I am currently working on we have a lot of different emails we want to send out to users and we would like to build those emails from templates. My goal was the leverage the ...
Fuente: http://www.joeyb.org/

Fecha: 07/04/2010
Aspectos importantes para evitar el síndrome "It works on my machine".Aspectos importantes para evitar el síndrome "It works on my machine".
ALT.NET dotnet .NET C# Agile BizTalk ASP.NET
Fuente: codebetter.com

Fecha: 07/04/2010
Los nuevos bloques de salida codificada <%: %> en ASP.NET 4 y MVC 2.Los nuevos bloques de salida codificada <%: %> en ASP.NET 4 y MVC 2.
ASP.NET, Visual Studio, ASP.NET 2.0, .NET
Fuente: weblogs.asp.net

Fecha: 07/04/2010
No te pierdas la celebración de Krasis por su décimo aniversario. ¡Felicidades!No te pierdas la celebración de Krasis por su décimo aniversario. ¡Felicidades!
1.- Ir a la tienda2.- Meter en el carrito lo que quieras comprar (una unidad de cada cosa máximo)3.- Y a la hora de pagar usar el siguiente cupón de descuento:
Fuente: http://www.jasoft.org/

Fecha: 07/04/2010
Uso de CopyModel (MVC Futures) para copiar valores de propiedades entre objetos de forma automática.Uso de CopyModel (MVC Futures) para copiar valores de propiedades entre objetos de forma automática.
Brad Wilson just mentioned that the MVC Futures library has a static ModelCopier class with a CopyModel(object from, object to) static method. It uses reflection to match properties with the same name and compatible types.
Fuente: weblogs.asp.net

Fecha: 06/04/2010
Propiedades automáticas, inicialización de colecciones y continuador implícito de líneas en VB 2010.Propiedades automáticas, inicialización de colecciones y continuador implícito de líneas en VB 2010.
ASP.NET, Visual Studio, ASP.NET 2.0, .NET
Fuente: weblogs.asp.net

Fecha: 06/04/2010




Vídeo sobre MVC 2 avanzado, de Brad Wilson. Muy interesante.Vídeo sobre MVC 2 avanzado, de Brad Wilson. Muy interesante.
My re-recorded Advanced ASP.NET MVC 2 video is available now. The original video, from my C4MVC presentation, turned out to have a combination of bad audio and bad video, most of which I take the blame for, so I re-recorded...
Fuente: bradwilson.typepad.com

Fecha: 05/04/2010
Parámetros opcionales y con nombre en C#, y su uso en acciones MVCParámetros opcionales y con nombre en C#, y su uso en acciones MVC
ASP.NET, Visual Studio, ASP.NET 2.0, .NET
Fuente: weblogs.asp.net

Fecha: 05/04/2010
Tras once años de desarrollo, ayer fue lanzado OpenSSL 1.0.Tras once años de desarrollo, ayer fue lanzado OpenSSL 1.0.
Here you can find hints to the regular news about the OpenSSL project. Check this table from time to time when you want to be up-to-date with the latest OpenSSL development.
Fuente: http://www.openssl.org/

Fecha: 30/03/2010
Activar/Desactivar el copiado y pegado de líneas en blanco en Visual Studio 2010.Activar/Desactivar el copiado y pegado de líneas en blanco en Visual Studio 2010.
As you may know, Visual Studio’s cut and copy commands are useful for more than just selected text. If you invoke them when there is no selection, VS will cut or copy your entire line, which saves you the trouble of selecting the line before adding it
Fuente: blogs.msdn.com

Fecha: 29/03/2010
Diferencias entre First() y Single() en LINQ.Diferencias entre First() y Single() en LINQ.
.NET, Software Architecture
Fuente: weblogs.asp.net

Fecha: 29/03/2010
Hanselman comenta las mejoras en el tiempo de arranque de aplicaciones ASP.NET 4.Hanselman comenta las mejoras en el tiempo de arranque de aplicaciones ASP.NET 4.
Scott Hanselman on Programming, User Experience, The Zen of Computers and Life in General
Fuente: http://www.hanselman.com/

Fecha: 29/03/2010
Implementando un captcha en un ActionResult, parte I.Implementando un captcha en un ActionResult, parte I.
Fuente: dotnetslackers.com

Fecha: 29/03/2010
Lanzado jQuery UI 1.8.Lanzado jQuery UI 1.8.
jQuery UI is jQuery's user interface library that comes with many widgets, interaction modules and themes.
Fuente: blog.jqueryui.com

Fecha: 26/03/2010
Algunos casos de éxito de ASP.NET MVC.Algunos casos de éxito de ASP.NET MVC.
Shiju Varghese's Blog on ASP.NET MVC
Fuente: weblogs.asp.net

Fecha: 26/03/2010
Convergencia VB y C# en las últimas versiones de los lenguajesConvergencia VB y C# en las últimas versiones de los lenguajes
C# 3 had new language extensions that are practical for every kind of application. No matter what application you’re creating, property initializers, collection initializers, Lambda expressions, LINQ… ...
Fuente: weblogs.thinktecture.com

Fecha: 25/03/2010
Mejoras en controles de datos disponibles en ASP.NET 4.Mejoras en controles de datos disponibles en ASP.NET 4.
This article, by Scott Mitchell, explores the enhancements made to the data Web controls in ASP.NET 4.0.
Fuente: http://www.4guysfromrolla.com/

Fecha: 25/03/2010
Facilitar el diagnóstico de problemas con ASP.NET MVC: unautilidad para mostrar información de entorno, versiones de ensamblados MVC, Futures, y algunas cosas más.Facilitar el diagnóstico de problemas con ASP.NET MVC: unautilidad para mostrar información de entorno, versiones de ensamblados MVC, Futures, y algunas cosas más.
When we released ASP.NET MVC 2, we included a file in the MvcFutures package (download) called MvcDiagnostics.aspx. This single WebForms page can be dropped into any MVC site, and then viewed in your browser. It will give you diagnostic information...
Fuente: bradwilson.typepad.com

Fecha: 25/03/2010
Uso de desplegables en ASP.NET MVC, partiendo de cero.Uso de desplegables en ASP.NET MVC, partiendo de cero.
DropDownLists in ASP.NET MVC seem to cause a fair amount of confusion to developers fresh from Web Forms World. This article looks to provide you with all (well, most) of what you need to know to get your DropDownLists working in ASP.NET MVC.
Fuente: http://www.mikesdotnetting.com/

Fecha: 24/03/2010

Y no olvides que, si te interesa, puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o siguiéndome en Twitter.

Publicado en: Variable not found