
Como recordaréis, hasta ese momento las acciones no tenían tipo de retorno, pero han replanteado el diseño para hacerlo más flexible, testable y potente. Así, pasamos de definir las acciones de esta forma:
public void Index()
{
RenderView("Index");
}
a esta otra:
public ActionResult Index()
{
return RenderView();
}
En el código anterior destacan dos aspectos. En primer lugar que la llamada a
RenderView()
no tiene parámetros; el sistema mostrará la vista cuyo nombre coincida con el de la acción que se está ejecutando (Index, en este caso). En segundo lugar, que la llamada a RenderView()
retorna un objeto ActionResult
(o más concretamente un descendiente, RenderViewResult
), que será el devuelto por la acción.De la misma forma, existen tipos de ActionResult concretos para retornar el resultado de las acciones más habituales:
RenderViewResult
, retornado cuando se llama desde el controlador aRenderView()
.ActionRedirectResult
, retornado al llamar aRedirectToAction()
HttpRedirectResult
, que será la respuesta a unRedirect()
EmptyResult
, que intuyo que será para casos en los que no hay que hacer nada (!), aunque todavía no le he visto mucho el sentido...
Además de las citadas anteriormente, una de las ventajas de retornar estos objetos desde los controladores es que podemos crear nuestra clase, siempre heredando de
ActionResult
, e implementar comportamientos personalizados.Esto es lo que ha hecho el genial Phil Haack en dos ejemplos recientemente publicados en su blog.
El primero de ellos, publicado en el post "Writing A Custom File Download Action Result For ASP.NET MVC" muestra una implementación de una acción cuya invocación hace que el cliente descargue, mediante un download, el archivo indicado, en su ejemplo, el archivo CSS de su sitio web:
public ActionResult Download()
{
return new DownloadResult
{ VirtualPath="~/content/site.css",
FileDownloadName = "TheSiteCss.css"
};
}
La clase
DownloadResult
una descendiente de ActionResult
, en cuya implementación encontraremos, además de la definición de las propiedades VirtualPath
y FileDownloadName
, la implementación del método ExecuteResult
, que será invocado por el framework al finalizar la ejecución de la acción, y donde realmente se realiza el envío al cliente del archivo, con parámetro content-disposition convenientemente establecido:public class DownloadResult : ActionResult
{
public DownloadResult()
{
}
public DownloadResult(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; set; }
public string FileDownloadName { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (!String.IsNullOrEmpty(FileDownloadName)) {
context.HttpContext.Response.AddHeader("content-disposition",
"attachment; filename=" + this.FileDownloadName)
}
string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
context.HttpContext.Response.TransmitFile(filePath);
}
}
El segundo ejemplo, publicado en el post "Delegating Action Result", vuelve a demostrar otro posible uso de los ActionResults creando un nuevo descendiente,
DelegatingResult
, que puede ser retornado desde las acciones para indicar qué operaciones deben llevarse a cabo por el framework.El siguiente código muestra cómo retornamos un objeto de este tipo, inicializado con una lambda:
public ActionResult Hello()
{
return new DelegatingResult(context =>
{
context.HttpContext.Response.AddHeader("something", "something");
context.HttpContext.Response.Write("Hello World!");
});
}
Como veremos a continuación, el constructor de este nuevo tipo recibe un parámetro de tipo
Action<ControllerContext>
y lo almacenará de forma local en la propiedad Command
, postergando su ejecución hasta más adelante; será la sobreescritura del método ExecuteResult
la que ejecutará el comando:public class DelegatingResult : ActionResult
{
public Action<ControllerContext> Command { get; private set; }
public DelegatingResult(Action<ControllerContext> command)
{
this.Command = command;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
Command(context);
}
}
Puedes ver el código completo de ambos ejemplos, así como descargar proyectos de prueba en los artículos originales de Phil Haack:
Por último, recordar que todos estos detalles son relativos a la última actualización de la preview de esta tecnología y podrían variar en futuras revisiones.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 10:00 p. m.
Etiquetas: .net, asp.net, aspnetmvc, c#, desarrollo, programación
Fisix, por ejemplo, es un motor de física en 2 dimensiones desarrollado en ActionScript 3.0 para desarrolladores de juegos o simuladores en Flash. Aunque en su web podéis encontrar más demos, incrusto una aquí para que os hagáis a la idea de lo que puede llegar a conseguirse con esta librería (podéis probar a arrastrar la muñeca por la pantalla o interactuar con los objetos).
Actualmente se encuentra en su versión alfa 0.5, y puede ser utilizado sin coste exclusivamente en proyectos no comerciales; para otros usos hay que contactar con el autor. En cualquier caso, por el tiempo que ha pasado desde su última actualización, parece que no está muy al día.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 9:55 p. m.
Etiquetas: curiosidades, desarrollo, motores de física

Como sabemos, si desde una aplicación queremos obtener una descripción comprensible de un elemento de una enumeración, normalmente no podemos realizar una conversión directa (
elemento.ToString()
) del mismo, pues obtenemos los nombres de los identificadores usados a nivel de código. La solución habitual, hasta la llegada de C# 3.0 consistía en incluir dentro de alguna clase de utilidad un conversor estático que recibiera como parámetro en elemento de la enumeración y retornara un string, algo así como:
public static string EstadoProyecto2String(EstadoProyecto e)
{
switch (e)
{
case EstadoProyecto.PendienteDeAceptacion:
return "Pendiente de aceptación";
case EstadoProyecto.EnRealizacion:
return "En realización";
case EstadoProyecto.Finalizado:
return "Finalizado";
default:
throw
new ArgumentOutOfRangeException("Error: " + e);
}
}
Este método, sin embargo, presenta algunos inconvenientes. En primer lugar, dado el tipado fuerte del parámetro de entrada del método, es necesario crear una función similar para cada enumeración sobre la que queramos realizar la operación.
También puede resultar peligroso separar la definición de la enumeración del método que transforma sus elementos a cadena de caracteres, puesto que puede perderse la sincronización entre ambos cuando, por ejemplo, se introduzca un nuevo elemento en ella y no se actualice el método con la descripción asociada.
La solución, que como he comentado me pareció muy interesante, consiste en decorar cada elemento de la enumeración con un atributo que describa al mismo, e implementar un método de extensión sobre la clase base
System.Enum
para obtener estos valores. Veamos cómo.Ah, una cosa más. Aunque los ejemplos están escritos en C#, se puede conseguir exactamente el mismo resultado en VB.NET simplemente realizando las correspondientes adaptaciones sintácticas. Podrás encontrarlo al final del post.
1. Declaración de la enumeración
Vamos a usar el atributoSystem.ComponentModel.DescriptionAttribute
, aunque podríamos usar cualquier otro que nos interese, o incluso crear nuestro propio atributo personalizado. El código de definición de la enumeración sería así:
using System.ComponentModel;
public enum EstadoProyecto
{
[Description("Pendiente de aceptación")] PendienteDeAceptacion,
[Description("En realización")] EnRealizacion,
[Description("Finalizado")] Finalizado,
[Description("Facturado y cerrado")] FacturadoYCerrado
}
2. Implementación del método de extensión
Ahora vamos a crear el método de extensión (¿qué son los métodos de extensión?) que se aplicará a todas las enumeraciones.Fijaos que el parámetro de entrada del método está precedido por la palabra reservada
this
y el tipo es System.Enum
, por lo que será aplicable a cualquier enumeración.
using System;
using System.ComponentModel;
using System.Reflection;
public static class Utils
{
public static string GetDescription(this Enum e)
{
FieldInfo field = e.GetType().GetField(e.ToString());
if (field != null)
{
object[] attribs =
field.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attribs.Length > 0)
return (attribs[0] as DescriptionAttribute).Description;
}
return e.ToString();
}
}

GetDescription()
, que nos devolverá el texto asociado al elemento de la enumeración; si éste no existe, es decir, si no se ha decorado el elemento con el atributo apropiado, nos devolverá el identificador utilizado.De esta forma eliminamos de un plumazo los dos inconvenientes citados anteriormente: la separación entre la definición de la enumeración y los textos descriptivos, y la necesidad de crear un conversor a texto por cada enumeración que usemos en nuestra aplicación.
Y por cierto, el equivalente en VB.NET completo sería:
Imports System.ComponentModel
Imports System.Reflection
Imports System.Runtime.CompilerServices
Module Module1
Public Enum EstadoProyecto
<Description("Pendiente de aceptación")> PendienteDeAceptacion
<Description("En realización")> EnRealizacion
<Description("Finalizado")> Finalizado
<Description("Facturado y cerrado")> FacturadoYCerrado
End Enum
<Extension()> _
Public Function GetDescription(ByVal e As System.Enum) As String
Dim field As FieldInfo = e.GetType().GetField(e.ToString())
If Not (field Is Nothing) Then
Dim attribs() As Object = _
field.GetCustomAttributes(GetType(DescriptionAttribute), False)
If attribs.Length > 0 Then
Return CType(attribs(0), DescriptionAttribute).Description
End If
End If
Return e.ToString()
End Function
End Module
Publicado en: www.variablenotfound.com.

El archivo distribuido, un zip, contiene siete chuletas en formato PDF:
- Extensiones a los tipos
String
yObject
- Extensiones a los tipos
Number
yError
- Referencia del tipo
DomEvent
- Extensiones al tipo
DomElement
- Extensiones a los tipos
Date
yBoolean
- Eventos del ciclo de vida en cliente
- Extensiones al tipo
Array
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 10:01 p. m.
Etiquetas: ajax, asp.net, chuletas, desarrollo, javascript, programación

C# 3.0 nos trae otra sorpresa, también relacionada con el establecimiento de valores iniciales de elementos: los inicializadores de colecciones. Aunque esta característica también estaba prevista para VB.Net 9.0, al final fue desplazada a futuras versiones por problemas de tiempo.
Para inicializar una colección, hasta ahora era necesario en primer lugar crear la clase correspondiente para, a continuación, realizar sucesivas invocaciones al método
Add()
con cada uno de los elementos a añadir: List<string> ls = new List<string>();
ls.Add("Uno");
ls.Add("Dos");
ls.Add("Tres");
C# 3.0 permite una alternativa mucho más elegante y rápida de codificar, simplemente se introducen los elementos a añadir a la colección entre llaves (como se hacía con los inicializadores de arrays o los nuevos inicializadores de objetos), separados por comas, como en el siguiente ejemplo:
List<string> ls =
new List<string>() { "Uno", "Dos", "Tres" };
Si desensamblamos el ejecutable resultante, podremos ver que es el compilador el que ha añadido por nosotros los
Add()
de cada uno de los elementos después de instanciar la colección:
newobj instance void class
[mscorlib]System.Collections.Generic.List`1<string>::.ctor()
stloc.s '<>g__initLocal0'
ldloc.s '<>g__initLocal0'
ldstr "Uno"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s '<>g__initLocal0'
ldstr "Dos"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s '<>g__initLocal0'
ldstr "Tres"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
Uniendo esto ahora con los inicializadores de objetos que ya tratamos un post anterior, fijaos en la potencia del resultado:
List<Persona> lp = new List<Persona>
{
new Persona { Nombre="Juan", Edad=34 },
new Persona { Nombre="Luis", Edad=53 },
new Persona { Nombre="José", Edad=23 }
};
Efectivamente, cada elemento es una nueva instancia de la clase Persona, con las propiedades que nos interesan inicializadas de forma directa. De hacerlo con los métodos tradicionales, para conseguir el mismo resultado deberíamos utilizar muuuchas más líneas de código.
Otro ejemplo que demuestra aún más la potencia de esta característica:
var nums = new SortedList
{
{ 34, "Treinta y cuatro" },
{ 12, "Doce" },
{ 3, "Tres" }
};
foreach (var e in nums)
Console.WriteLine(e.Key + " " + e.Value);
En el código anterior podemos ver, primero, el uso de variables locales de tipo implícito, para ahorrarnos tener que escribir más de la cuenta. En segundo lugar, se muestra cómo se inicializa una colección cuyo método
Add()
requiere dos parámetros. En el caso de un SortedList<TKey, TValue>
, su método Add()
requiere la clave de ordenación y el valor del elemento.(Obviamente, el resultado de la ejecución del código anterior será la lista ordenada por su valor numérico (Key))
En conclusión, se trata de otra de las innumerables ventajas que nos ofrece la nueva versión de C# destinadas a evitarnos pulsaciones innecesarias, y a la que seguro le daremos uso.
Publicado en: www.variablenotfound.com.
Puedes descargarla pulsando sobre la imagen:

Si quieres leer más sobre estos operadores, puedes probar también en la referencia oficial, The .Net Standard Query Operators [ING], a leer este artículo traducido por el maestro Octavio Hernández, profundizar en MSDN, o en otros de los muchos sitios con información relacionada, como la referencia de Hooked On Linq [ING].
Publicado en: http://www.variablenotfound.com/.

jQuery, para que el no haya oído hablar de ella, es una librería Javascript destinada a facilitar enormemente la vida a los desarrolladores simplificando y unificando el manejo de eventos, la manipulación del contenido (DOM), estilos, el uso de Ajax, la creación de animaciones y efectos gráficos, y un larguísimo etcétera propiciado por la facilidad para añadirle plugins que extienden sus funcionalidades iniciales. Y todo ello de forma muy rápida, sin excesivas complicaciones, y sin añadir demasiado peso a las páginas.
En este post vamos a ver un ejemplo de integración de jQuery con ASP.NET MVC framework realizando una aplicación muy sencilla e ilustrativa que nos enseñará cómo enviar información desde el cliente al servidor y actualizar porciones de página completas con el retorno de éste, respetando en todo momento la filosofía MVC.
El funcionamiento será realmente simple: el usuario introduce su nombre y edad, y al pulsar el botón se enviará esta información al servidor, que la utiliza para componer una respuesta y mandarla de vuelta al cliente. Cuando éste la recibe, la mostrará (con un poco de 'magia' visual de jQuery) y transcurridos unos segundos, desaparecerá de forma automática. La siguiente captura muestra el sistema que vamos a construir en ejecución:
Pero antes de entrar en faena, unos comentarios. En primer lugar, sólo voy a explicar los aspectos de interés para la realización del ejemplo, partiendo de las plantillas adaptadas para Web Developer Express 2008. Si prefieres antes una introducción sobre el framework, puedes visitar las magníficas traducciones de Thinking in .Net de los tutoriales de Scott Guthrië sobre MVC. Se refieren a la primera preview, pero los fundamentos son igualmente válidos.
Segundo, supongo que funcionará con versiones superiores de Visual Studio, pero no he podido comprobarlo. Está creado y comprobado con Visual Web Developer Express, y la Preview 2 del framework MVC.
Y por último, decir que el ejemplo completo podrás descargarlo usando el enlace que encontrarás al final del post. :-)
Primero: Estructuramos la solución
En líneas generales, nuestra aplicación tendrá los siguientes componentes:- Tendremos un controlador principal, llamado Home. En él crearemos dos acciones, las dos únicas que permite nuestra aplicación: una, llamada Index, que se encargará de mostrar la página inicial del sistema, y otra llamada Welcome, que a partir de los datos introducidos por el usuario maquetará el interfaz del mensaje de saludo.
- Como consecuencia del punto anterior, dispondremos de dos vistas. La primera, Index compondrá la interfaz principal con el formulario, y la segunda, que llamaremos Welcome, que define la interfaz del saludo al usuario (el recuadro de color amarillo chillón ;-)).
Esta última vista necesitará los datos de la persona (nombre y edad) para poder mostrar correctamente su mensaje, por lo que el controlador deberá enviárselos después de obtenerlos de los parámetros de la petición.
Fijaos que respetamos en todo momento el patrón MVC haciendo que el cliente invoque a la acción Welcome del controlador usando Ajax, y que la composición del interfaz (HTML) se realice a través de la vista correspondiente. Utilizaremos, por tanto, toda la infraestructura del framework MVC, sin modificaciones. - También, para añadir algo de emoción, he incluido una página maestra, que definirá el interfaz general de las páginas del sistema y realizará la inclusión de los archivos adicionales necesarios, como las hojas de estilo y scripts como jQuery.
Segundo: implementamos el controlador
El controlador de nuestra aplicación va a ser bien simple. Lo vemos y comentamos seguidamente:public class HomeController : Controller
{
public void Index()
{
RenderView("Index");
}
public void Welcome(string name, int age)
{
Person person =
new Person { Age = age, Name = name };
RenderView("Welcome", person);
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Podemos observar la clase
HomeController
que implementa las acciones del controlador Home. La acción Index provoca la visualización de la vista de su mismo nombre. La acción Welcome, es algo más compleja; en primer lugar, se observa que recibe dos parámetros, en nombre y edad del usuario, que utiliza para montar un objeto de tipo
Person
, definido algo más abajo, que posteriormente envía a la vista a la hora de renderizarla. Habréis observado aquí la utilización de inicializadores de objetos en la instanciación, y de propiedades automáticas en la definición del tipo.Tercero: implementamos las vistas
Recordemos que vamos a implementar dos vistas, una para la página principal (llamada Index), que mostrará el formulario de entrada de datos, y otra (que llamaremos Welcome) que definirá el interfaz de la respuesta del servidor. Comenzaremos describiendo cómo incluir jQuery en nuestras páginas, y pasaremos después a ellas.3.1. Inclusión de jQuery
Para implementar las vistas necesitamos antes preparar la infraestructura. En primer lugar, descargamos jQuery desde la web oficial del proyecto, y la introducimos en nuestro proyecto. Si vas a descargar la solución completa desde aquí, en ella ya viene incluido el archivo.A continuación, es un buen momento para modificar la página maestra e incluir en ella la referencia a esta librería:
<script type="text/javascript"
src="/scripts/jquery-1.2.3.min.js">
</script>
Un inciso importante aquí. Hace unas semanas se publicó un HotFix para Visual Studio 2008 y Web Developer Express que corrije, entre otras, deficiencias en el intellisense y hacen posible el uso de esta magnífica ayuda cuando escribimos código jQuery. Altamente recomendable, pues, instalarse esta actualización.
Sin embargo, el hecho de introducir en la página maestra la referencia a la librería jQuery hace que el intellisense no funcione como debe. Por tanto, aunque no es la opción que he elegido en este proyecto, podríais incluir el script directamente en la vista Index en lugar de en la Master, y así disfrutaréis del soporte a la codificación.
3.2. La vista "Index"
Esta vista será la encargada de mostrar el formulario e implementar la lógica de cliente necesaria para obtener los datos del usuario, enviarlos al servidor y actualizar el interfaz con el retorno. Su implementación se encuentra en el archivo Index.aspx.Desde el punto de vista del interfaz de usuario es bastante simple, lo justo para mostrar un par de inputs con sus correspondientes etiquetas y el botón que iniciará la fiesta llamando a la función
send()
:<form action="" id="myForm">
<label for="name">Name: </label><input type="text" id="name" />
<br />
<label for="age">Age: </label><input type="text" id="age" size="2" />
<br />
<button id="btn" onclick="send(); return false;">Send!</button>
</form>
<hr />
<div id="result" style="display: none; width: 400px"></div>
Observad que no es necesario establecer un action en el formulario, ni otros de los atributos habituales, pues éste no se enviará (de hecho, el formulario incluso sería innecesario). Fijaos también que el evento
onclick
del botón retorna false, para evitar que se produzca un postback (¡aaargh, palabra maldita! ;-)) del formulario completo.Puede verse también un
div
llamado "result", inicialmente invisible, que se utilizará de contenedor para mostrar las respuestas obtenidas desde el servidor.Pasemos ahora al script. La función
send()
invocada como consecuencia de la pulsación del botón pinta así: function send()
{
var name = document.getElementById("name").value;
var age = document.getElementById("age").value;
updateServerText(name, age);
}
En realidad no hace gran cosa: obtiene el valor de los textboxes y llama a la función que realmente hace el trabajo duro. Este hubiera sido un buen sitio para poner validadores, pero eso os lo dejo de deberes ;-).
El código de la función
updateServerText()
es el siguiente: function updateServerText(name, age)
{
document.getElementById("btn").disabled = true;
$.ajax({
cache: false,
url: '<%= Url.Action("Welcome", "Home") %>',
data: {
Name: name,
Age: age
},
success: function(msg) {
$("#result").html(msg).show("slow");
},
error: function(msg) {
$("#result").html("Bad parameters!").show("slow");
}
});
setTimeout(function () {
document.getElementById("btn").disabled = false;
$("#result").hide("slow");
}, 3000);
}
En primer lugar, se desactiva el botón de envío para evitar nuevas pulsaciones hasta que nos interese. He utilizado un método habitual del DOM,
getElementById()
para conseguirlo, no encontré una alternativa mejor en jQuery.A continuación se utiliza el método
ajax
de jQuery para realizar la llamada al servidor. Aunque existen otras alternativas de más alto nivel y por tanto más fáciles de utilizar, elegí esta para tener más control sobre lo que envío, la forma de hacerlo y la respuesta. Los parámetros utilizados en la llamada a
$.ajax
son:cache
, con el que forzamos la anulación de caché, obligando a que cada llamada se ejecute totalmente, sin utilizar el contenido almacenado en cliente. Internamente, jQuery añade al querystring un parámetro aleatorio, con lo que consigue que cada llamada sea única.url
, la dirección de invocación de la acción, que se genera utilizando el método de ayudaUrl.Action()
, pasándole como parámetros el controlador y la acción, lo que retornará la URL asociada en el sistema de rutas definido. En condiciones normales, si la aplicación se ejecuta sobre el raíz del servidor web, se traducirá por '/Home/Welcome'.data
, los datos a enviar, que se establecen en formato JSON, donde cada propiedad va seguida de su valor. jQuery tomará estos valores y los transformará en los parámetros que necesita la acción Welcome, por lo que el nombre de las propiedades deberá corresponder con los parámetros que espera esta acción (Name y Age).sucess
define la función de retorno exitoso, que mostrará los datos recibidos del servidor introduciéndolos en el contenedor "result". Y ya que estamos, gracias a la magia de jQuery, se mostrará con un efecto visual muy majo.error
, define una función de captura de errores para casos extraños, por si todo falla. Por ejemplo, dado que no estamos validando la entrada del usuario, si éste introduce texto en la edad, el framework no será capaz de realizar la conversión para pasarle los parámetros al controlador y fallará estrepitosamente; en este caso simplemente mostraremos un mensaje de error en cliente.
Fijaos que la llamada a la acción (Welcome) del controlador (Home) es capturada por el framework y dirigida al método correspondiente sin necesidad de hacer nada más, dado que se trata de una llamada HTTP normal. De hecho, si sobre el navegador se introduce la dirección "http://localhost:[tupuerto]/Home/Welcome?Name=Peter&Age=12" podremos ver en pantalla el mismo resultado que recibirá la llamada Ajax.

Obviamente, este efecto podría ser controlado y hacer que sólo se respondieran peticiones originadas a través de Ajax y similares.
Por último, continando con el código anterior, dejamos programado un timer para que unos segundos más tarde, el mensaje mostrado, sea cual sea el resultado de la llamada Ajax, desaparezca lentamente y, de paso, se active de nuevo el botón de envío. El efecto, ya lo veréis si ejecutáis la solución, es de lo más vistoso, creando una sensación de interactividad y dinamismo muy a lo 2.0 que está tan de moda.
3.3. La vista "Welcome"
En esta vista definiremos el interfaz del mensaje que mostraremos al usuario cuando introduzca su información y pulse el botón de envío. Dado que estamos usando MVC, la llamada Ajax descrita anteriormente llegará al controlador y éste hará que la vista cree el interfaz que será devuelto al cliente.La vista, por tanto, es como cualquier otra, salvo algunas diferencias interesantes. Por ejemplo, no tiene página maestra, no la necesita; de hecho ni siquiera tiene la estructura de una página HTML completa, sólo de la porción que necesita para montar su representación. El código de Welcome.aspx, salvo las obligatorias directivas iniciales, es:
<div style="background-color: Yellow; border: 1px solid black;">
<em>Message from server (<%=DateTime.Now %>):</em><br />
Hi, <%= ViewData.Name %>, your age is <%= ViewData.Age %>
</div>
Pero aún queda un detalle que afinar. En el archivo code-behind (o codefile) donde se define la clase
Welcome
hay que indicar expresamente que la clase es una vista de un tipo concreto de la siguiente forma: public partial class Views_WebParts_Welcome : ViewPage<Person>
{
}
De esta forma indicamos que los datos de la vista son del tipo
Person
, lo que nos permite beneficiarnos del tipado fuerte en la composición de la misma; de hecho, esto es lo que permite que podamos usar tan alegremente una expresión como ViewData.Age
a la hora de componer el interfaz.Fijaos que aunque en este ejemplo no hemos hecho ninguna composición compleja y los datos que hemos usado, contenidos en
ViewData
, han sido obtenidos por el Controlador directamente de la vista, sería exactamente igual si se tratara de algo menos simple, como una página concreta de datos obtenidos desde el Modelo, por ejemplo con Linq, y mostrados en forma de grid. Cuarto: recapitulamos
Hemos visto, paso a paso, un ejemplo de cómo podemos utilizar el framework MVC de Microsoft para el desarrollo de aplicaciones web que hacen uso de Ajax, utilizando para ello la excelente librería de scripting jQuery.Para ello hemos creado una vista que es la página Web con el formulario principal, y otra vista parcial con el fragmento compuesto por el servidor con la información recibida. El controlador, por su parte, incluye acciones para responder a las peticiones del cliente independientemente de si se originan a través de Ajax o mediante la navegación del usuario, mostrando la vista oportuna.
La modificación dinámica del interfaz, así como las llamadas asíncronas al servidor, encajan perfectamente en la filosofía MVC teniendo en cuenta algunas reglas básicas, como el respeto a las responsabilidades de cada capa.
Y ahora, lo prometido:

Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 10:05 p. m.
Etiquetas: ajax, asp.net, aspnetmvc, javascript, jquery

Recordemos que una parte de una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el compilador eliminará tanto la declaración del método como las llamadas que se hagan al mismo.
Sin embargo esta eliminación pueden causar efectos no deseados difíciles de detectar.
Veámoslo con un ejemplo. Supongamos una clase parcial como la siguiente, que representa a una variable de tipo entero que puede ser incrementada o decrementada a través de métodos:
public partial class Variable
{
partial void Log(string msg);
private int i = 0;
public void Inc()
{
i++;
Log("Incremento. I: " + i);
}
public void Dec()
{
Log("Decremento. I: " + (--i));
}
public int Value
{
get { return i; }
}
}
Creamos ahora un código que utiliza esta clase de forma muy simple: crea una variable, la incrementa dos veces, la decrementa una vez y muestra el resultado:
Variable v = new Variable();
v.Inc();
v.Inc();
v.Dec();
Console.WriteLine(v.Value);
Obviamente, tras la ejecución de este código la pantalla mostrará por consola un "1", ¿no? Claro, el resultado de realizar dos incrementos y un decremento sobre el cero.
Pues no necesariamente. De hecho, es imposible conocer, a la vista del código mostrado hasta ahora, cuál será el resultado mostrado por consola al finalizar la ejecución. Dependiendo de la existencia de la implementación del método parcial
Log()
, declarado e invocado en la clase Variable
anterior, puede ocurrir:- Si existe otra porción de la misma clase (otra
partial class Variable
) donde se implemente el método, se ejecutará éste. El valor mostrado por consola, salvo que desde esta implementación se modificara el valor del campo privado, sería "1". - Si no existe una implementación del método
Log()
en la clase, el compilador eliminará todas las llamadas al mismo. Pero si observáis, esto incluye el decremento del valor interno, que estaba en el interior de la llamada como un autodecremento:
Por tanto, en este caso, el compilador eliminará tanto la llamada aLog("Decremento. I: " + (--i));
Log()
como la operación que se realiza en el interior. Obviamente, el resultado de ejecución de la prueba anterior sería "2".
Lo mismo ocurriría si el resultado a mostrar fuera el valor de retorno de una llamada a otra función: esta no se ejecutaría, lo cual puede ser grave si en ella se realiza una operación importante, como por ejemplo:public function InicializaValores()
{
Log("Elementos reestablecidos: " + reseteaElementos() );
}
Por ejemplo, imaginad que el ejemplo anterior contiene una implementación de
Log()
; la aplicación funcionaría correctamente. Sin embargo, si pasado un tiempo se decide eliminar esta implementación (por ejemplo, porque ya no es necesario registrar las operaciones realizadas), la operación de decremento (Dec()
) dejaría de funcionar. Aunque, eso sí, no es nada que no se pueda solucionar con un buen juego de pruebas...
Publicado en: http://www.variablenotfound.com/.

Estos métodos, declarados en el contexto de una clase parcial, permiten comunicar de forma segura los distintos fragmentos de dicha clase. De forma similar a los eventos, permiten que un código incluya una llamada a una función que puede (o no) haber sido implementada por un código cliente, aunque en este caso obligatoriamente la implementación se encontrará en uno de los fragmentos de la misma clase desde donde se realiza la llamada.
En la práctica significa que una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el código correspondiente a la llamada será eliminado en tiempo compilación para optimizar el resultado... ¡sí, eliminado!
Por ejemplo, el siguiente código muestra una declaración de un método parcial en el interior de una clase, y su utilización desde dentro de uno de sus métodos:
// C#
public partial class Ejemplo
{
// El método parcial se declara
// sin implementación...
partial void Log(string msg);
public void RealizarAlgo()
{
hacerAlgoComplejo();
Log("¡Ojo!"); // Usamos el método
// parcial declarado antes
}
[...] // Otros métodos y propiedades
}
' VB.NET
Partial Public Class Ejemplo
' El método parcial se declara, sin
' implementar nada en el cuerpo
Partial Private Sub Log(ByVal msg As String)
End Sub
Public Sub RealizarAlgo()
HacerAlgoComplejo()
Log("¡Ojo!") ' Usamos el método parcial
End Sub
[...] ' Otros métodos y propiedades
End Class
Y esta la parte realmente curiosa. Cuando el compilador detecta la invocación del método parcial
Log()
, buscará en todos los fragmentos de la clase a ver si existe una implementación del mismo. Si no existe, eliminará del ensamblado resultante la llamada a dichos métodos, es decir, actuará como si éstas no existieran en el código fuente.En caso afirmativo, es decir, si existen implementaciones como las del siguiente ejemplo, todo se ejecutará conforme a lo previsto:
// C#
public partial class Ejemplo
{
partial void Log(string msg)
{
Console.WriteLine(msg);
}
}
' VB.Net
Partial Public Class Ejemplo
Private Sub Log(ByVal msg As String)
Console.WriteLine(msg)
End Sub
End Class
Antes comentaba que los métodos parciales son, en cierto sentido, similares a los eventos, pues conceptualmente permiten lo mismo: pasar el control a un código cliente en un momento dado, en el caso de que éste exista. De hecho, hay muchos desarrolladores que lo consideran como un sustituto ligero a los eventos, pues permite prácticamente lo mismo pero se implementan de forma más sencilla.
Existen, sin embargo, algunas diferencias entre ambos modelos, como:
- Los métodos parciales se implementan en la propia clase, mientras que los eventos pueden ser consumidos también desde cualquier otra
- El enlace, o la suscripción, a eventos es dinámica, se realiza en tiempo de ejecución, es necesario incluir código para ello; los métodos parciales, sin embargo, se vinculan en tiempo de compilación
- Los eventos permiten múltiples suscripciones, es decir, asociarles más de un código cliente
- Los eventos pueden presentar cualquier visibilidad (pública, privada...), mientras que los métodos parciales son obligatoriamente privados.
Por último, es conveniente citar algunas consideraciones sobre los métodos parciales:
- Deben ser siempre privados (ya lo había comentado antes)
- No deben devolver valores (en VB.Net serían
SUB
, en C# serían de tipovoid
) - Pueden ser estáticos (shared en VB)
- Pueden usar parámetros, acceder a los miembros privados de la clase... en definitiva, actuar como un método más de la misma
En resumen, los métodos parciales forman parte del conjunto de novedades de C# y VB.Net que no son absolutamente necesarias y que a veces pueden parecer incluso diabólicas, pues facilitan la dispersión de código y dificultan la legibilidad. Además, en breve publicaré un post comentando posibles efectos laterales a tener en cuenta cuando usemos los métodos parciales en nuestros desarrollos.
Sin embargo, es innegable que los métodos parciales nos facilitan enormemente la inclusión de código de usuario en el interior de clases generadas de forma automática. Por ejemplo, el diseñador visual del modelo de datos de LinqToSQL genera los
DataContext
como clases parciales, en las que define un método parcial llamado OnCreated()
. Si el usuario quiere incluir alguna inicialización personal al crear los DataContext, no tendrá que tocar el código generado de forma automática; simplemente creará otro fragmento de la clase parcial e implementará este método, de una forma mucho más natural y cómoda que si se tratara de un evento.Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 9:10 p. m.
Etiquetas: .net, c#, desarrollo, programación, vb.net, vs2008

"Al utilizar la funcion ValidatorEnable para habilitar un validador, me activa automaticamente la validacion, y me muestra el texto que pongo para cuando la validacion no se cumpla, como puedo evitar esto"
Recordemos que el post trataba sobre cómo conseguir, desde Javascript, habilitar o deshabilitar validadores de controles incluidos en un webform utilizando la función
ValidatorEnable()
, que pone a nuestra disposición ASP.Net.El problema, como comenta Pablo, es que al habilitar la validación desde script se muestran de forma automática los mensajes de error en todos aquellos controles que no sean válidos, provocando un efecto que puede resultar desconcertante para el usuario.
Indagando un poco, he comprobado que el problema se debe a que
ValidatorEnable()
, después de habilitar el validator, comprueba si los valores del control son correctos, mostrando el error en caso contrario.Existen al menos dos formas de solucionar este problema.
La primera consiste en jugar con la visibilidad del mensaje de error. Como se observa en el siguiente código, al llamar a la función
HabilitaValidador()
, ésta llamará a ValidatorEnable
y acto seguido, si el control no es válido, oculta el mensaje de error:
function HabilitaValidador(validator, habilitar)
{
ValidatorEnable(validator, habilitar);
if (habilitar && !validator.isvalid)
validator.style.visibility = "hidden";
}
La segunda forma consiste en simular el comportamiento interno de
ValidatorEnable
, pero eliminando la llamada a la comprobación de la validez del control.
function HabilitaValidador(validator, habilitar)
{
validator.enabled = habilitar;
}
Como se puede ver, simplemente se está estableciendo la propiedad
enabled
del validador, sin realizar ninguna comprobación posterior.En ambos casos, la forma de utilizar esta función desde script sería la misma:
function activar()
{
HabilitaValidador("<%= RequiredFieldValidator1.ClientID %>", true);
}
Para mi gusto la opción más limpia, aunque sea jugando con la visibilidad de los elementos, es la primera de las mostradas, pues se respeta el ciclo completo de validación. En el segundo método nos estamos saltando las validaciones y el seguimiento de la validez global de la página, que la función original
ValidatorEnable
sí contempla.Espero que esto resuelva la duda.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 6:15 p. m.
Etiquetas: asp.net, consultas, javascript, trucos, validadores

Este es el segundo post de la serie compuesta por:
- 101 citas célebres del mundo de la informática
- Otras 101 citas célebres del mundo de la informática (este post)
- Y todavía otras 101 citas célebres del mundo de la informática
- 101 nuevas citas célebres del mundo de la informática (¡y van 404!)
Publicado por José M. Aguilar a las 10:00 p. m.
Etiquetas: buenas prácticas, curiosidades, desarrollo, frases célebres, humor, programación

Las clases parciales (llamados también tipos parciales) son una característica presente en algunos lenguajes de programación, como C# y VB.Net, que permiten que la declaración de una clase se realice en varios archivos de código fuente, rompiendo así la tradicional regla "una clase, un archivo". Será tarea del compilador tomar las porciones de los distintos archivos y fundirlas en una única entidad.
En VB.Net y C#, a diferencia de otros lenguajes, es necesario indicar explícitamente que una clase es parcial, es decir, que es posible que haya otros archivos donde se continúe la declaración de la misma, usando en ambos con la palabra clave
partial
en la definición del tipo: ' VB.NET
Public Partial Class Persona
...
End Class
// C#
public partial class Persona
{
...
}
En este código hemos visto cómo se declara una clase parcial en ambos lenguajes, que es prácticamente idéntica salvo por los detalles sintácticos obvios. Por ello, a partir de este momento continuaré introduciendo los ejemplos sólo en C#.
Pero antes un inciso: la única diferencia entre ambos, estrictamente hablando, es que C# obliga a que todas las apariciones de la clase estén marcadas como parciales, mientras que en VB.Net puede dejarse una de ellas (llamémosla "declaración principal") sin indicar que es parcial, y especificarlo en el resto de apariciones. En mi opinión, esta no es una práctica recomendable, por lo que aconsejaría utilizar el modificador
partial
siempre que la clase lo sea, e independientemente del lenguaje utilizado, pues contribuirá a la mantenibilidad del código.El número de partes en las que se divide una clase es indiferente, el compilador tomará todas ellas y generará en el ensamblado como si fuera una clase normal.
Para comprobarlo he creado un pequeño código con dos clases exactamente iguales, salvo en su nombre. Una de ellas se denomina
PersonaTotal
, y está definida como siempre, en un único archivo; la otra, PersonaParcial
, es parcial y la he troceado en tres archivos, como sigue: // *** Archivo PersonaParcial.Propiedades.cs ***
// Aquí definiremos todas las propiedades
partial class PersonaParcial
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
}
// *** Archivo PersonaParcial.IEnumerable.cs ***
// Aquí implementaremos el interfaz IEnumerable
partial class PersonaParcial: IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
// *** Archivo PersonaParcial.Metodos.cs ***
// Aquí implementaremos los métodos que necesitemos
partial class PersonaParcial
{
public override string ToString()
{
return Nombre + " " + Apellidos;
}
}
Y efectivamente, el resultado de compilar ambas clases, según se puede observar con ILDASM es idéntico:

A la hora de crear clases parciales es conveniente tener los siguientes aspectos en cuenta:
- Los atributos de la clase resultante serán la combinación de los atributos definidos en cada una de las partes.
- El tipo base de los distintos fragmentos debe ser el mismo, o aparecer sólo en una de las declaraciones parciales.
- Si se trata de una clase genérica, los parámetros deben coincidir en todas las partes.
- Los interfaces que implemente la clase resultante será la unión de todos los implementados por las distintas secciones.
- De la misma forma, los miembros (métodos, propiedades, campos...) de la clase final será la unión de todos los definidos en las distintas partes.
Vale, ya hemos visto qué son y cómo se usan, pero, ¿para qué sirven? ¿cuándo es conveniente utilizarlas? Pues bien, son varios los motivos de su existencia, algunos discutibles y otros realmente interesantes.
En primer lugar, no era sencillo que varios desarrolladores trabajaran sobre una misma clase de forma concurrente. Incluso utilizando sistemas de control de versiones (como Sourcesafe o Subversion), la unidad mínima de trabajo es el archivo de código fuente, y la edición simultánea podía generar problemas a la hora de realizar fusiones de las porciones modificadas por cada usuario.
En segundo lugar, permite que clases realmente extensas puedan ser troceadas para facilitar su comprensión y mantenimiento. Igualmente, puede utilizarse para separar código en base a distintos criterios:
- por ejemplo, separar la interfaz (los miembros visibles desde el exterior de la clase) y por otra los miembros privados a la misma
- o bien separar las porciones que implementan interfaces, o sobreescriben miembros de clases antecesoras de los pertenecientes a la propia clase
- o separar temas concernientes a distintos dominios o aspectos
Así, es posible que un desarrollador y un generador estén introduciendo cambios sobre la misma clase sin molestarse, cada uno jugando con su propia porción de la clase; el primero puede introducir funcionalidades sin preocuparse de que una nueva generación automática de código pueda machacar su trabajo. Visual Studio y otros entornos de desarrollo hacen uso intensivo de esta capacidad, por ejemplo, en los diseñadores visuales de Windows Forms, WPF, ASP.Net e incluso el generador de modelos de LinqToSql.
Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 9:30 p. m.
Etiquetas: .net, c#, desarrollo, programación, trucos, vb.net

Google nos tiene acostumbrados a implementar APIs muy sencillas de usar, y en este caso no podía ser menos. Para demostrarlo, vamos a crear una página web con un sencillo traductor en Javascript, comentando paso por paso lo que hay que hacer para que podáis adaptarlo a vuestras necesidades.
Paso 1: Incluir el API
La inclusión de las funciones necesarias para realizar la traducción es muy sencilla. Basta con incluir el siguiente código, por ejemplo, en la sección HEAD de la página: <script type="text/javascript"
src="http://www.google.com/jsapi">
</script>
<script type="text/javascript">
google.load("language", "1");
</script>
El primer bloque descarga a cliente la librería javascript Ajax API Loader, el cargador genérico de librerías Ajax utilizado por Google. Éste se usa en el segundo bloque script para cargar, llamando a la función
google.load
el API "language" (traductor), en su versión 1 (el segundo parámetro).Paso 2: Creamos el interfaz
Nuestro traductor será realmente simple. Además, vamos a contemplar un pequeño subconjunto de los idiomas permitidos para no complicar mucho el código, aunque podéis añadir todos los que consideréis necesarios.El resultado será como el mostrado en la siguiente imagen.

El código fuente completo lo encontraréis al final del post, por lo que no voy a repetirlo aquí. Simplemente indicar que tendremos un
TextArea
donde el usuario introducirá el texto a traducir, dos desplegables con los idiomas origen y destino de la traducción, y un botón que iniciará la acción a través del evento onclick
. Por último, se reservará una zona en la que insertaremos el resultado de la traducción.Ah, un detalle interesante: en el desplegable de idiomas de origen se ha creado un elemento en el desplegable "Auto", cuyo valor es un string vacío; esto indicará al motor de traducción que infiera el idioma a partir del texto enviado.
Paso 3: ¡Traducimos!
La pulsación del botón provocará la llamada a la funciónOnclick()
, desde donde se realizará la traducción del texto introducido en el TextArea.Como podréis observar en el código, en primer lugar obtendremos los valores de los distintos parámetros, el texto a traducir y los idiomas origen y destino, y lo introducimos en variables para facilitar su tratamiento.
var text = document.getElementById("text").value;
var srcLang = document.getElementById("srcLang").value;
var dstLang = document.getElementById("dstLang").value;
Acto seguido, realizamos la llamada al traductor. El primer parámetro será el texto a traducir, seguido de los idiomas (origen y destino), y por último se introduce la función callback que será invocada cuando finalice la operación; hay que tener en cuenta que la traducción es realizada a través de una llamada asíncrona a los servidores de Google:
google.language.translate(text, srcLang, dstLang, function(result)
{
if (!result.error)
{
var resultado = document.getElementById("result");
resultado.innerHTML = result.translation;
}
else alert(result.error.message);
}
);
Como podéis observar, y es quizás lo único extraño que tiene esta instrucción, el callback se ha definido como una función anónima definida en el espacio del mismo parámetro (podéis ver otro ejemplo de este tipo de funciones cuando explicaba cómo añadir funciones con parámetros al evento OnLoad).
Para los queráis jugar con esto directamente, ahí va el código listo para un copiar y pegar.
<html>
<head>
<title>Traductor</title>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("language", "1");
</script>
</head>
<body>
<textarea id="text" rows="8" cols="40">Hi, how are you?</textarea>
<br />
<button onclick="onClick()">
Traducir</button>
Del idioma
<select id="srcLang">
<option value="">(Auto)</option>
<option value="es">Español</option>
<option value="en">Inglés</option>
<option value="fr">Francés</option>
</select>
Al
<select id="dstLang">
<option value="es">Español</option>
<option value="en">Inglés</option>
<option value="fr">Francés</option>
</select>
<h3>Traducción:</h3>
<div id="result">
(Introduce un texto)
</div>
</body>
<script type="text/javascript">
function onClick()
{
// obtenemos el texto y los idiomas origen y destino
var text = document.getElementById("text").value;
var srcLang = document.getElementById("srcLang").value;
var dstLang = document.getElementById("dstLang").value;
// llamada al traductor
google.language.translate(text, srcLang, dstLang, function(result)
{
if (!result.error)
{
var resultado = document.getElementById("result");
resultado.innerHTML = result.translation;
}
else alert(result.error.message);
}
);
}
</script>
</html>
Enlaces: Página oficial de documentación del API
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 10:00 p. m.
Etiquetas: desarrollo, google, html, javascript, programación, servicios on-line, web
Existe una versión de este post ampliada y actualizada a la versión 1.0 de ASP.NET MVC: ASP.NET MVC: trece preguntas básicas

<disclaimer>
Algunas de las respuestas podríamos considerarlas como beta, y pueden variar con el tiempo. Son opiniones, ideas y conjeturas sobre un producto nuevo y que todavía está en desarrollo, así que usadlas con precaución. ;-)</disclaimer>
1. Empecemos desde el principio, ¿qué es MVC?
Aunque de forma algo simplista, podríamos definir MVC como un patrón arquitectural que describe una forma de desarrollar aplicaciones software separando los componentes en tres grupos (o capas):- El Modelo que contiene una representación de los datos que maneja el sistema, su lógica de negocio, y sus mecanismos de persistencia.
- La Vista, o interfaz de usuario, que compone la información que se envía al cliente y los mecanismos interacción con éste.
- El Controlador, que actúa como intermediario entre el Modelo y la Vista, gestionando el flujo de información entre ellos y las transformaciones para adaptar los datos a las necesidades de cada uno.
Puedes encontrar más información en:
- Wikipedia, Modelo-Vista-Controlador
- Documentos originales de definición de MVC, de Trygve M. H. Reenskaug, en Xerox (¡año 1978!)
- Tutorial de Java, Arquitectura MVC
- Model-View-Controller Web presentation pattern en MSDN
2. ¿Qué ventajas tiene el uso del patrón MVC?
Como siempre, esto de enumerar ventajas es algo subjetivo, por lo que puede que pienses que falta o sobra alguna (¡dímelo!). En un primer asalto, podríamos aportar las siguientes:- Clara separación entre interfaz, lógica de negocio y de presentación, que además provoca parte de las ventajas siguientes.
- Sencillez para crear distintas representaciones de los mismos datos.
- Facilidad para la realización de pruebas unitarias de los componentes, así como de aplicar desarrollo guiado por pruebas (TDD).
- Reutilización de los componentes.
- Simplicidad en el mantenimiento de los sistemas.
- Facilidad para desarrollar prototipos rápidos.
- Los desarrollos suelen ser más escalables.
- Tener que ceñirse a una estructura predefinida, lo que a veces puede incrementar la complejidad del sistema. Hay problemas que son más difíciles de resolver respetando el patrón MVC.
- La curva de aprendizaje para los nuevos desarrolladores se estima mayor que la de modelos más simples como Webforms.
- La distribución de componentes obliga a crear y mantener un mayor número de ficheros.
3. ¿Qué es ASP.Net MVC Framework?
Es un framework, un entorno de trabajo que está creando Microsoft, que nos ayudará a desarrollar aplicaciones que sigan la filosofía MVC sobre ASP.Net. Su versión final incluirá librerías (ensamblados), plantillas y herramientas que se integrarán en Visual Studio 2008. ScottGu, en su presentación del framework el pasado Octubre en las conferencias Alt.Net, ya adelantó las principales características, y puedes ampliar información en la página oficial.Actualmente (marzo 2008) puede descargarse la Preview 2 del framework, e incluso su código fuente ha sido publicado en CodePlex. Aunque "de fábrica" no soporta las versiones Express de Visual Studio, en este mismo blog puedes encontrar algunas plantillas y ejemplos de ASP.NET MVC. También hay quien la ha echado a andar en Mono.
4. ¿Es el primer framework MVC creado para .Net?
No, ni el único. Existen multitud de frameworks MVC para ASP.Net, como MonoRail, Maverick.Net, ProMesh.Net y muchos otros.5. Como desarrollador de aplicaciones web con ASP.Net, ¿me afectará la llegada de este framework?
No necesariamente. Puedes seguir desarrollando aplicaciones como hasta ahora, con Webforms. Si así lo decides, este nuevo framework no te afectará nada; simplemente, ignóralo.De todas formas, ya que has leído hasta aquí, permíteme un consejo: aprende MVC framework. Después podrás decidir con conocimiento de causa si te conviene o no.
6. ¿Significa la aparición del framework MVC la muerte próxima de los Webforms de ASP.Net?
En absoluto. Son simplemente dos filosofías diferentes para conseguir lo mismo, ¡páginas web!.La tecnología de Webforms es muy útil para asemejar el desarrollo de aplicaciones web a las de escritorio, ocultando la complejidad derivada del entorno desconectado y stateless (sin conservación de estado) del protocolo HTTP a base de complejos roundtrips, postbacks y viewstates, lo que nos permite crear de forma muy productiva formularios impresionantes y que el funcionamiento de nuestra aplicación esté guiado por eventos, como si estuvieramos programando Winforms.
Sin embargo, esta misma potencia a veces hace que las páginas sean pesadas y difícilmente mantenibles, y además se dificultan enormemente la realización de pruebas. Y por no hablar de comportamientos extraños cuando intentamos intervenir en el ciclo de vida de las páginas, por ejemplo para la carga y descarga de controles dinámicos.
ASP.Net MVC propone una forma distinta de trabajar, más cercana a la realidad del protocolo y, curiosamente, más parecida a cómo se hacía unos años atrás, cuando controlábamos cada byte que se enviaba al cliente. No existen, por tanto, conceptos como el mantenimiento del estado en el viewstate, ni el postback, ni nos valdrán los controles de servidor basados en estas características, la mayoría. Sin embargo, dado que el framework está creado sobre ASP.Net, será posible utilizar páginas maestras, codificar las vistas en un .aspx utilizando C# o VB.Net, usar los mecanismos de seguridad internos, control de caché, gestión de sesiones, localización, etc; además, seguro que en un futuro no demasiado lejano comenzarán a surgir miles de componentes o controles reutilizables que nos ayudarán a mejorar la productividad.
7. ¿Vale la pena pasarse a ASP.Net MVC o sigo usando Webforms?
Todavía lo estoy estudiando ;-). Hay muchos aspectos a valorar.No hay que olvidar que los Webforms son una buena opción, tanto como lo han sido hasta ahora. Sobre todo si el equipo de desarrollo tiene ya experiencia creando aplicaciones con esta tecnología y se dispone de controles reutilizables propios o ajenos, deberíamos pensárnoslo antes de dar el salto a ASP.Net MVC. Tened en cuenta que la productividad, al menos inicialmente, va a caer.
Sin embargo, las ventajas de la arquitectura MVC y del propio framework descritas anteriormente son un buen aliciente para comenzar: testing, URLs amigables, separación de aspectos, mantenibilidad... Por otra parte, todavía es pronto para conocer el nivel de las herramientas de desarrollo (a nivel de IDE, librerías de controles, helpers) que aparecerán con la versión final, y las que surgirán desde la propia comunidad de desarrolladores, por lo que no es posible evaluar el impacto en la productividad que tendrá la adopción de esta nueva forma de trabajar.
Y, por cierto, si te preocupa el futuro de los Webforms, has de saber que Microsoft va a seguir dándoles soporte y mejorándolos, como no podía ser de otra forma. Por tanto, de momento no es necesario que bases tu decisión en esto.
8. ¿Se puede utilizar el ASP.Net Ajax con el framework MVC?
De momento parece que no, o al menos no de la forma en que se hace actualmente, dado que los controles de servidor (runat="server"
), como el UpdatePanel
, no están integrados en este modelo. De hecho, ya ni siquiera tienen sentido los formularios runat="server"
, por lo que menos aún los controles que dependían de éstos.Se prevé que se creará un API específico para permitir desde cliente, mediante scripting, hacer llamadas a los controladores, y actualizar porciones de contenido de la página con el marcado que nos envíe la vista correspondiente. Pero esto son sólo conjeturas de momento, ya se irá aclarando conforme el producto se acerque a su versión final.
9. ¿Puedo usar Linq desarrollando aplicaciones con ASP.Net MVC framework?
Sí, de hecho se complementan a la perfección.Por ejemplo, las clases del modelo podrán generarse de forma automática (y completa para aplicaciones relativamente simples) con los diseñadores visuales de LinqToSQL o LinqToEntities desde Visual Studio 2008 o de forma externa con herramientas como SQLMetal. Además, el controlador podrán utilizar expresiones de consulta para solicitar datos desde el modelo, o enviar datos actualizados usando las capacidades ORM de estas tecnologías.
10. ¿Será ASP.Net MVC framework software libre?
Pues claro que no ;-). Se podrá acceder al código fuente (de hecho, ya se puede), que será distribuido de la misma forma que el de .Net framework, pero no será software libre. Si buscas una solución open source, revisa la pregunta número 4.Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 9:00 p. m.
Etiquetas: asp.net, aspnetmvc, desarrollo, frameworks, web

Por ejemplo, ¿recuerdas el nombre en clave de ASP.NET Ajax? ¿Y de Windows 95? ¿Y sabes que tecnología se esconde detrás de Whistler o de Avalon?
Por suerte, en la Wikipedia, que hay de todo, alguien se ha encargado de recoger, si no todos los Codenames, al menos muchos de ellos.
Enlace: List of Microsoft codenames
Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 8:55 p. m.
Etiquetas: curiosidades, microsoft, servicios on-line

Aunque su licencia no permite redistribuir los binarios resultantes para evitar que posibles versiones alternativas del framework circulen por ahí, es muy interesante, sin duda, ver las "tripas" de esta nueva criatura.
Y, por cierto, también carga en Visual C# 2008 Express Edition...
Publicado en: http://www.variablenotfound.com/.

Concretamente, se trata de una adaptación de Phil Haack para la CTP2 de una aplicación creada inicialmente por Brad Abrams que muestra un catálogo de productos categorizado, tomados de la clásica base de datos NorthWind (para SQLServer/Express), y permite la creación, edición y eliminación de los mismos (CRUD); en otras palabras, una mini-aplicación completa. El acceso a datos se realiza mediante Linq, y las clases del Modelo se han generado con el diseñador Linq2SQL.
Aparte de la adaptación, he aprovechado para retocarla un poco, y le he añadido algunas funcionalidades y detalles que no estaban implementados. Faltan algunos flequillos, como las validaciones de formularios que todavía no he visto cómo se resuelven en el framework, pero bueno, lo que hay es una base interesante para comenzar o seguir profundizando en esta tecnología.
Podéis descargar el proyecto desde el enlace que encontraréis más abajo. Una vez descomprimido el archivo, abrid la carpeta desde Visual Web Developer Express (opción "Abrir > Abrir sitio web" o "File > Open web site" si tenéis aún la versión en inglés) y listo, podéis pulsar F5 para ejecutar.
Por cierto, no sé si funcionará bien con las versiones "pro" de Visual Studio 2008. Agradecería que si alguien lo prueba en este entorno, me lo comentara.
Enlaces:

Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 9:50 p. m.
Etiquetas: asp.net, aspnetmvc, desarrollo, programación, web

Se trata de un entorno de desarrollo integrado (IDE) para la plataforma .NET en el que el equipo del proyecto Mono anda trabajando desde hace varios años. Su objetivo inicial era facilitar una herramienta libre y gratuita para Linux, MacOS e incluso Windows, que permita la creación de aplicaciones en C# y otros lenguajes .NET, aunque después ha evolucionado hasta convertirse en una plataforma extensible sobre la que podría encajar cualquier tipo de herramienta de desarrollo.
- Se trata de un entorno muy personalizable, permitiendo la creación de atajos de teclado, la redistribución de elementos en pantalla o inclusión de herramientas externas.
- Soporta varios lenguajes, como C#, VB.Net o C/C++ o incluso Boo y Java (IKVM) a través de plugins externos.
- Ayuda en la escritura del código (auto-completar, información de parámetros... al más puro estilo intellisense).
- Incluye herramientas de refactorización, como renombrado de tipos y miembros, encapsulación de campos, sobreescritura de métodos o autoimplementación de interfaces.
- Ayudas en la navegación a través del código, como saltar a las declaraciones de variables, o búsquedas de clases derivadas.
- Diseñador de interfaces para aplicaciones GTK# y soporte para librerías de widgets.
- Control de versiones integrado, con soporte para Subversion.
- Pruebas unitarias integradas, utilizando NUnit.
- Soporte para proyectos ASP.Net.
- Servidor web integrado (XSP) para pruebas.
- Explorador y editor de bases de datos integrados (aún en beta).
- Integración con Monodoc, para la documentación de clases.
- Soporte para makefiles, tanto para generación como para sincronización.
- Soporte para formatos de proyecto Visual Studio 2005.
- Sistema de empaquetado que genera tarballs, código fuente y binarios.
- Línea de comandos para generar y gestionar proyectos.
- Soporte para proyectos de localización.
- Arquitectura extensible a través de plugins.
Información mucho más detallada, eso sí, en inglés, en la web del proyecto.
Publicado en: http://www.variablenotfound.com/.
Publicado por José M. Aguilar a las 11:58 a. m.
Etiquetas: .net, desarrollo, herramientas, mono, noticias