<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-897874347676011387</id><updated>2012-02-16T07:22:05.811+01:00</updated><category term='wcf'/><category term='facebook'/><category term='presentaciones'/><category term='pure'/><category term='raona'/><category term='tfs'/><category term='sql server compact'/><category term='javascript'/><category term='visual basic'/><category term='catdotnet'/><category term='NoSql'/><category term='auges'/><category term='caliburn'/><category term='C#'/><category term='win32'/><category term='otros'/><category term='guille'/><category term='opinion'/><category term='grandes dilemas'/><category term='wpf'/><category term='html'/><category term='asp.net MVC'/><category term='patrones'/><category term='geeks.ms'/><category term='surface'/><category term='framework'/><category term='culturilla'/><category term='c++'/><category term='depuración'/><category term='prism'/><category term='unity'/><title type='text'>burbujas en .NET</title><subtitle type='html'>Mi blog sobre desarrollo en .NET :)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default?start-index=101&amp;max-results=100'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>147</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-1407296646503224116</id><published>2011-08-10T18:25:00.001+02:00</published><updated>2011-08-10T18:25:47.602+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# Básico: Objetos y referencias</title><content type='html'>&lt;p&gt;La verdad es que ahora hacía bastantes meses que no publicaba nada de la serie “C# básico”. En esta serie pongo posts sobre temas básicos del lenguaje. No es un libro por fascículos, ni un tutorial al uso puesto que los posts no tienen orden en concreto y &lt;em&gt;nacen&lt;/em&gt; a partir de inquietudes que observo (mayoritariamente en los foros, pero también por correos que recibo). Todos &lt;a href="http://geeks.ms/blogs/etomas/archive/tags/c_2300_+basico/default.aspx" target="_blank"&gt;los posts de esta serie los podéis ver aquí&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;En el post de hoy quiero hablar de la diferencia entre objetos y referencias ya que observo que no siempre está clara. Gente que entiende los conceptos básicos de &lt;em&gt;&lt;a href="http://geeks.ms/blogs/etomas/archive/2010/07/14/c-b-225-sico-191-que-es-la-herencia.aspx" target="_blank"&gt;herencia&lt;/a&gt;&lt;/em&gt; parece liarse en este punto. Muchas veces es un tema pasado rápidamente en muchos libros y tutoriales. Y es que, la verdad, es un tema muy sencillo… ;-) &lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;MiClase miObjeto = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MiClase();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Qué hace este código? En muchos sitios leerás que lo que hace es crear un objeto de la clase &lt;em&gt;MiClase&lt;/em&gt;. Eso es cierto, pero describe lo que hace lo que hay &lt;em&gt;a la derecha&lt;/em&gt; del símbolo de asignación. Qué hace el código que está a la &lt;em&gt;izquierda&lt;/em&gt;? Pues lo que hace es &lt;em&gt;declarar una referencia de tipo MiClase&lt;/em&gt;. Otra palabra que se usa muchas veces en lugar de referencia es &lt;em&gt;variable&lt;/em&gt; aunque no son técnicamente lo mismo (hay variables que no son referencias y las referencias pueden asignarse a otros elementos que no llamamos usualmente variables como p.ej. los parámetros a una función).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Las referencias contienen objetos. Yo prefiero decir que las referencias &lt;em&gt;apuntan a&lt;/em&gt; objetos (aunque esta palabra parece como “maldita”, sin duda por culpa de los punteros) para que quede claro que &lt;strong&gt;un mismo objeto puede estar contenido en (apuntado por) más de una referencia&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;El tipo de una referencia&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Todas las refencias tienen un tipo. Este tipo &lt;strong&gt;es único e inmutable durante toda la vida de la referencia.&lt;/strong&gt; El tipo de una referencia determina que objetos puede contener dicha referencia. En concreto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Objetos del mismo tipo. Es decir, una referencia de tipo MiClase puede contener objetos de la clase MiClase. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Objetos de una clase derivada de la clase del tipo de la referencia. Si la referencia es de tipo MiClase puede contener objetos de cualquier clase derivada de MiClase. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Objetos de cualquier clase que implemente el tipo de la referencia. Eso aplica sólo si el tipo de la referencia es una interfaz. En este caso la referencia puede contener un objeto de cualquier clase que implemente dicha interfaz. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Todas las clases en .NET &lt;strong&gt;derivan de Object&lt;/strong&gt;. Por lo tanto, según el punto (2) una referencia de tipo Object, puede contener cualquier objeto de cualquier clase:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Object objeto = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CualquierClase();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Condiciona alguna cosa más el tipo de la referencia? Pues sí: el tipo de la referencia condiciona &lt;em&gt;como vemos al objeto contenido en dicha referencia.&lt;/em&gt; Es decir, la referencia &lt;em&gt;es como un disfraz&lt;/em&gt; para el objeto. Le permite “ocultar su tipo real” y mostrarse como el “tipo de la referencia”.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;P.ej. dado el siguiente código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MiClase&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Foo() {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MiClaseDerivada : MiClase&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Bar() {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;MiClase c1 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MiClaseDerivada();&lt;br /&gt;MiClaseDerivada c2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MiClaseDerivada();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Podemos ver como &lt;em&gt;MiClase&lt;/em&gt; define un método (Foo) y &lt;em&gt;MiClaseDerivada&lt;/em&gt; que deriva de MiClase añade el método Bar. Luego c1 es una referencia de tipo MiClase que contiene un objeto de MiClaseDerivada (puede según el punto 2 anterior). Y c2 es una referencia de tipo MiClaseDerivada que contiene un objeto de MiClaseDerivada (posible según el punto 1 anterior). Entonces tenemos que:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;c1.Foo();   &lt;span style="color: #008000"&gt;// Ok.&lt;/span&gt;&lt;br /&gt;c1.Bar();   &lt;span style="color: #008000"&gt;// No compila.&lt;/span&gt;&lt;br /&gt;c2.Foo();   &lt;span style="color: #008000"&gt;// Ok.&lt;/span&gt;&lt;br /&gt;c2.Bar();   &lt;span style="color: #008000"&gt;// Ok.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La llamada c1.Bar() &lt;strong&gt;no compila&lt;/strong&gt;. ¿Por que? Pues simplemente porque la referencia es de tipo MiClase. Y MiClase no tiene ningún método Bar. Da igual que el objeto contenido por dicha referencia sea de tipo MiClaseDerivada, que sí que tiene el método Bar. El &lt;strong&gt;compilador no se fija en los tipos de los objetos. Se fija en los tipos de las referencias&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Objetos compartidos&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Como hemos dicho antes un mismo objeto puede estar contenido por más de una referencia:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;MiClaseDerivada c1 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MiClaseDerivada();&lt;br /&gt;MiClase c2 = c1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este punto &lt;strong&gt;tenemos dos referencias. Pero un sólo objeto&lt;/strong&gt;. Es decir, c1 y c2 contienen el mismo objeto, que es un objeto de tipo MiClaseDerivada. Si accedo al objeto a través de c1 lo veo como un objeto de tipo MiClaseDerivada (ya que este es el tipo de c1). Por otro lado si accedo al objeto a través de c2 lo veo como un objeto de tipo MiClase (al ser este el tipo de c2). Por lo tanto c1.Bar() es correcto y c2.Bar() no compila.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero insisto: son el &lt;strong&gt;mismo&lt;/strong&gt; objeto. Observad el siguiente código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Program&lt;br /&gt; {&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main()&lt;br /&gt;     {&lt;br /&gt;         MiClaseDerivada c1 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MiClaseDerivada();&lt;br /&gt;         MiClase c2 = c1;&lt;br /&gt;         c1.Incrementar();&lt;br /&gt;         c2.Incrementar();&lt;br /&gt;         Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;El valor de c1 es:&amp;quot;&lt;/span&gt; + c1.Valor);&lt;br /&gt;         Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;El valor de c2 es:&amp;quot;&lt;/span&gt; + c2.Valor);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MiClase&lt;br /&gt; {&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; valor;&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Valor { get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.valor; } }&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Incrementar()&lt;br /&gt;     {&lt;br /&gt;         valor++;&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;  MiClaseDerivada : MiClase&lt;br /&gt; {&lt;br /&gt;     &lt;span style="color: #008000"&gt;// Código&lt;/span&gt;&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Cual es la salida por pantalla de dicho código? Pensadlo con detenimiento. Pues&amp;#160; la siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;font face="Courier New"&gt;El valor de c1 es:2 &lt;br /&gt;    &lt;br /&gt;El valor de c2 es:2&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Eso es debido porque c1 y c2 contienen el mismo objeto. Por lo tanto inicialmente tenemos que el valor de dicho objeto es 0. Al llamar a c1.Incrementar() el valor pasa a ser 1. Y al llamar a c2.Incrementar(), el valor pasa a ser 2, ya que el objeto que contiene c2 &lt;strong&gt;es el mismo&lt;/strong&gt; que el objeto que contiene c1.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues recordadlo siempre: &lt;strong&gt;Asignar una referencia a otra NO crea un nuevo objeto. Simplemente hace que la referencia contenida a la izquierda de la asignación contenga EL MISMO objeto que la referencia situada a la derecha&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Comparando objetos y referencias.&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De nuevo la forma más fácil es verlo con un código de ejemplo:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Program&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main()&lt;br /&gt;    {&lt;br /&gt;        Persona p1 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Persona();&lt;br /&gt;        p1.Nombre = &lt;span style="color: #006080"&gt;&amp;quot;Pepito&amp;quot;&lt;/span&gt;;&lt;br /&gt;        p1.Edad = 20;&lt;br /&gt;        Persona p2 = p1;&lt;br /&gt;        Persona p3 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Persona();&lt;br /&gt;        p3.Nombre = &lt;span style="color: #006080"&gt;&amp;quot;Pepito&amp;quot;&lt;/span&gt;;&lt;br /&gt;        p3.Edad = 20;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; b = p2 == p1;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; b2 = p3 == p2;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Persona&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Nombre { get; set; }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Edad { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Cual es el valor de b y b2?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;b vale &lt;em&gt;true&lt;/em&gt; porque p1 y p2 contienen el mismo objeto &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;b2 vale &lt;em&gt;false&lt;/em&gt; porque p3 y p2 contienen objetos distintos. Da igual que los dos objetos sean del mismo tipo y sean idénticos. En este caso son dos &lt;em&gt;Personas&lt;/em&gt; idénticas: mismo nombre y edad. Pero el operador == compara referencias, no objetos. &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues recuerda: El operador == al comparar referencias devuelve &lt;em&gt;true&lt;/em&gt; sólo si las dos referencias contienen el mismo objeto. En caso contrario devuelve&lt;em&gt; false&lt;/em&gt; (aunque las dos referencias apunten a dos objetos idénticos).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Este comportamiento del operador == puede &lt;strong&gt;modificarse&lt;/strong&gt; para que compare el valor de los objetos en lugar de indicar si las dos referencias contienen el mismo objeto. P.ej. la clase string tienen modificado dicho operador para comparar el &lt;em&gt;valor&lt;/em&gt; de las cadenas. Esto queda fuera del alcance de este post.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La comparación de objetos (es decir, determinar si dos objetos son idénticos pese a ser dos objetos distintos) es algo que por norma general depende de la clase. P.ej. dos Personas serán iguales si tienen el mismo nombre y edad. Dos cadenas serán iguales si contienen los mismos carácteres. Depende de cada clase &lt;em&gt;determinar que significa que dos objetos son iguales&lt;/em&gt;. Para estandarizar un poco la comparación de objetos, en .NET tenemos el método Equals. Dicho método está definido en la clase Object y por lo tanto, por herencia, existe en todas las clases. Si quiero indicarle al framework como comparar dos objetos de tipo Persona puedo añadir a la clase Persona el siguiente código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; Equals(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (obj &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; Persona)&lt;br /&gt;    {&lt;br /&gt;        Persona otro = (Persona) obj;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; otro.Edad == Edad &amp;amp;&amp;amp;&lt;br /&gt;               otro.Nombre == Nombre;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y para comparar los objetos, debo llamar a Equals en lugar del operador ==&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; b2 = p3.Equals(p2);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Conversiones (castings)&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En el código del método Equals anterior hay el siguiente código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Persona otro = (Persona)obj;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El código (Persona) es lo que se llama casting. El casting lo que hace es &lt;strong&gt;cambiar el tipo de una referencia&lt;/strong&gt;. Es decir en el caso anterior obj era una referencia de tipo object (los parámetros también pueden ser referencias). Recordad que las referencias de tipo object pueden contener cualquier objeto. Pero yo quiero acceder a Nombre y Edad que son campos definidos en la clase Persona y por ello necesito una referencia de tipo Persona que me contenga el mismo objeto que la referencia obj.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si directamente probáramos:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Persona otro = obj;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Dicho código no compila. ¿Porque? Pues porque otro es una referencia de tipo Persona y por lo tanto solo puede contener:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Un objeto de tipo Persona &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Un objeto de cualquier clase que derive de Persona &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero obj es una referencia de tipo object y puede contener un objeto de tipo object o bien un objeto de cualquier clase que derive de object… es decir, de cualquier clase. Imaginad, entonces:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro();&lt;br /&gt;Persona otro = obj;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es evidente que el objeto contenido por obj es un perro y no una persona. Si el código de la segunda línea compilase estaríamos viendo un perro como una persona y bueno… se supone que no se puede, no? Por eso, como el compilador no puede garantizar que el objeto (recordad que el compilador no se fija en objetos) contenido por la referencia obj sea de un tipo válido para la referencia otro, se cura en salud y no nos deja compilar el código.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero… tu no eres el compilador y tu sí te fijas en los objetos. ¿Qué pasa en aquellos casos en que &lt;strong&gt;tu sabes&lt;/strong&gt; que el objeto contenido por la referencia obj es de un tipo válido para la referencia Persona? Pues que debes decírselo al compilador. ¿Cómo? Usando el casting:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Persona otro = (Persona)obj;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Aquí le estás diciendo al compilador: &lt;strong&gt;Quiero que la referencia otro contenga el mismo objeto que la referencia obj y tranquilo, no te quejes porque yo te digo que el objeto es de tipo Persona&lt;/strong&gt;. Con el casting el compilador te cree y te deja hacer la asignación.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Eh… que te crea el compilador no significa que te crea el CLR. El CLR no se fía ni de su madre, así que si tu haces:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; perro = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro();&lt;br /&gt;Persona persona = (Persona)perro;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El compilador no se quejará, pero cuando ejecutes, vas a recibir una hermosa InvalidCastException. El CLR sí que se fija en los objetos, como tu :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ah! Y aunque el compilador no se fije en objetos… no lo insultes, eh? No intentes algo como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Perro perro = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro();&lt;br /&gt;Persona persona = (Persona)perro;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Eso no compila. La razón es porque no es necesario fijarse en los objetos para ver que una referencia de tipo Persona &lt;strong&gt;nunca podrá contener el mismo objeto&lt;/strong&gt; que una referencia de tipo Perro: Persona y Perro no tienen nada en común. El compilador puede no fijarse en los objetos, pero no es tonto!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-1407296646503224116?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/1407296646503224116/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=1407296646503224116' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1407296646503224116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1407296646503224116'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/08/c-basico-objetos-y-referencias.html' title='C# Básico: Objetos y referencias'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-2195611769531033427</id><published>2011-05-11T22:28:00.001+02:00</published><updated>2011-05-11T22:28:39.416+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='auges'/><title type='text'>[Webcast–AUGES] Introducción a ASP.NET MVC</title><content type='html'>&lt;p&gt;Seguramente la mayoría ya sabréis que gracias al empuje del maestro &lt;a href="http://geeks.ms/blogs/lruiz/" target="_blank"&gt;Luis Ruiz Pavón&lt;/a&gt; (que nos ha ido &lt;em&gt;convenciendo&lt;/em&gt; a varios), se ha creado &lt;a href="http://www.auges.org/" target="_blank"&gt;AUGES&lt;/a&gt;, el grupo de usuarios de ASP.NET de España.&lt;/p&gt;  &lt;p&gt;Para mi es un honor y un placer poder formar parte de este grupo, pero todavía es un placer más grande inaugurar la agenda de eventos del grupo. Y como no podía ser de otro modo el evento será un Webcast de ASP.NET MVC. :) &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;La fecha? El Miércoles 18. La hora? A las 19:30&lt;/strong&gt; (hora española peninsular).&lt;/p&gt;  &lt;p&gt;La idea es hacer un evento 100% introductorio: explicar que es esto de ASP.NET MVC, ver ejemplos y comentar cosillas básicas. Más adelante ya tendremos tiempo de hacer eventos más &lt;em&gt;hardcore&lt;/em&gt; sobre el tema! ;-)&lt;/p&gt;  &lt;p&gt;Así que, ya sabes… si has oído a hablar de MVC y quieres ver de que se trata, o si conoces implementaciones de MVC en otros sistemas y quieres ver la de Microsoft, o si simplmente quieres escucharme un rato (mmmm…. :p) pásate por la web de &lt;a href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032486954&amp;amp;EventCategory=4&amp;amp;culture=es-ES&amp;amp;CountryCode=ES" target="_blank"&gt;registro&lt;/a&gt; y… nos conectamos el miércoles!!&lt;/p&gt;  &lt;p&gt;Saludos… y nos vemos! ;-)&lt;/p&gt;  &lt;p&gt;PD: Como siempre… crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog de geeks.ms&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-2195611769531033427?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/2195611769531033427/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=2195611769531033427' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2195611769531033427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2195611769531033427'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/05/webcastauges-introduccion-aspnet-mvc.html' title='[Webcast–AUGES] Introducción a ASP.NET MVC'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-891662789394928287</id><published>2011-04-03T21:09:00.001+02:00</published><updated>2011-04-03T21:09:02.844+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>[ASP.NET MVC] Pasar parámetros a través del PathInfo</title><content type='html'>&lt;p&gt;¡Muy buenas! Bueno, el título del post no queda demasiado claro, pero a ver si consigo explicar un poco la idea. ;-)&lt;/p&gt;  &lt;p&gt;Los que habéis usado ASP.NET MVC estáis muy acostumbradas a las URLs del estilo /controlador/accion/id, es decir algo como:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;/Home/Index/10 &lt;/li&gt;    &lt;li&gt;/Articles/View/Eiximenis &lt;/li&gt;    &lt;li&gt;/Blog/View/10293 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Sabemos que gracias a la tabla de rutas podemos pasar tantos parámetros como queramos, y así podríamos tener URLs del tipo:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;/Articles/View/Eiximenis/MVC/2011 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Que podría devolverme los articulos de “Eiximenis” con el tag “MVC” y del año 2011. &lt;/p&gt;  &lt;p&gt;El único punto a tener presente es que &lt;em&gt;el orden de los parámetros importa&lt;/em&gt;, es decir no es lo mismo /Articles/View/Eiximenis/MVC/2011 que /Articles/View/2011/MVC/Eiximenis. En el primer caso buscamos los artículos de Eiximenis sobre MVC en el 2011 y en el segundo caso buscaríamos los artículos del &lt;em&gt;blogger&lt;/em&gt; 2011, sobre MVC en el año de Eiximenis. Y sin duda &lt;a href="http://es.wikipedia.org/wiki/Francesc_Eiximenis"&gt;Fra Francesc Eiximenis&lt;/a&gt;, fue un gran escritor, pero que yo sepa todavía no se le ha dedicado un año (algo totalmente injusto, por supuesto :p).&lt;/p&gt;  &lt;p&gt;En este artículo quiero enseñaros una manera para que podáis gestionar URLs del tipo:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;/Articles/View/Author/Eiximenis/Tag/MVC/Year/2011 &lt;/li&gt;    &lt;li&gt;/Articles/View/Tag/MVC/Year/2011/Author/Eiximenis &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Y que ambas URLs sean tratadas de forma idéntica. En este caso estaríamos pasando tres parámetros: Author, Tag y Year.&lt;/p&gt;  &lt;p&gt;Para conseguir este efecto nos bastan dos acciones muy simples: definir un route handler nuevo y una entrada a la tabla de rutas.&lt;/p&gt;  &lt;p&gt;El route handler lo único que debe hacer es recoger la información de la URL y parsearla en “tokens” (usando el ‘/’ como separador). Y por cada par de tokens añadir una entrada en los valores de ruta (route values). El código es muy simple:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UrlRouteHandler : MvcRouteHandler&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IHttpHandler GetHttpHandler(RequestContext requestContext)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; path = requestContext.RouteData.Values[&lt;span style="color: #006080"&gt;&amp;quot;pathInfo&amp;quot;&lt;/span&gt;];&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (path != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; tokens = path.ToString().Split(&lt;span style="color: #006080"&gt;'/'&lt;/span&gt;);&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; idx =0; idx&amp;lt;tokens.Length; idx+=2)&lt;br /&gt;            {&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (idx+1 &amp;lt; tokens.Length)&lt;br /&gt;                {&lt;br /&gt;                    requestContext.RouteData.Values.Add(tokens[idx], tokens[idx+1]);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.GetHttpHandler(requestContext);&lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Una pequeña nota es que la cadena que separamos en tokens, no es toda la URL sino “pathInfo” un parámetro de ruta que ya nos vendrá dado. Este parámetro de ruta contendrá todo aquello que no es ni el controlador ni la acción. Es decir en la URL /Articles/View/Author/Eiximenis/Tag/MVC/Year/2011 el valor de pathInfo será Author/Eiximenis/Tag/MVC/Year/2011 (que son justo los parámetros).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora nos queda añadir la entrada a la tabla de rutas. En mi ejemplo yo he eliminado la entrada “Default” que genera VS2010 y la he sustituído por:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;routes.Add(&lt;span style="color: #006080"&gt;&amp;quot;Default&amp;quot;&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Route(url: &lt;span style="color: #006080"&gt;&amp;quot;{controller}/{action}/{*pathInfo}&amp;quot;&lt;/span&gt;,&lt;br /&gt;    routeHandler: &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UrlRouteHandler(),&lt;br /&gt;    defaults: &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; {controller = &lt;span style="color: #006080"&gt;&amp;quot;Home&amp;quot;&lt;/span&gt;, action = &lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;})));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La clave aquí está en el {*pathInfo}. Aquí le digo al sistema de rutas que coja todo lo que venga después de /{controller}/{action} y me lo añada a un parámetro de ruta llamado pathInfo. Además de eso, en esta ruta le indico que su routeHandler será una instancia de la clase UrlRouteHandler que hemos creado antes.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Una vez los datos están en el route value ya puede entrar en acción el sistema de binding de ASP.NET MVC lo que quiere decir que puedo crear un controlador como el siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ArticlesController : Controller&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult View(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; author, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; tag, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;? year)&lt;br /&gt;    {&lt;br /&gt;        dynamic data = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ExpandoObject();&lt;br /&gt;        data.Author = author ?? &lt;span style="color: #006080"&gt;&amp;quot;Sin formato&amp;quot;&lt;/span&gt;;&lt;br /&gt;        data.Tag = tag ?? &lt;span style="color: #006080"&gt;&amp;quot;Sin confirmación&amp;quot;&lt;/span&gt;;&lt;br /&gt;        data.Year = year.HasValue ? year.ToString() : &lt;span style="color: #006080"&gt;&amp;quot;Sin año&amp;quot;&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(data);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Que recibiría los parámetros de las URLs que hemos visto anteriormente.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo a todos!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;PD: &lt;/strong&gt;De nuevo eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-891662789394928287?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/891662789394928287/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=891662789394928287' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/891662789394928287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/891662789394928287'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/04/aspnet-mvc-pasar-parametros-traves-del.html' title='[ASP.NET MVC] Pasar parámetros a través del PathInfo'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-2013364878969497136</id><published>2011-03-28T17:33:00.001+02:00</published><updated>2011-03-28T17:33:57.707+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>[HTML/JS] Module pattern</title><content type='html'>&lt;p&gt;Muy buenas! Cuando creas un sitio web, es normal que vayas añadiendo cada vez más código javascript en él. Al final, seguramente terminaréis desarollando una mini-api, propia que muchas veces reside en un archivo .js, lleno de funciones. Algo como:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; HazAlgo(id, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt;, callback)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; _HazAlgoHelper(domObj, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este caso tenemos dos funciones, HazAlgo y _HazAlgoHelper. La función _HazAlgoHelper es realmente una función &lt;em&gt;privada&lt;/em&gt;, es decir está pensada para ser llamada únicamente dentro de HazAlgo. Pero en Javascript no existe directamente el concepto de &lt;em&gt;función privada&lt;/em&gt; así que le ponemos un idicador (que empieze por _) y asumimos que todas las funciones que empiecen por _, son privadas.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Como podemos ver, el código javascript no está muy “organizado”: tenemos todas las funciones juntas y además podemos ver aquellas que no deberíamos. El patrón de módulo existe para solventar esos problemas.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;El patrón de módulo&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La idea del patrón de módulo (module pattern) en Javascript es simular el concepto de una clase estática con métodos públicos y métodos privados. Lo de clase estática viene porque no quiero ir creando objetos de mi módulo, simplemente quiero &lt;em&gt;tener ahí&lt;/em&gt;, las funciones públicas. Pero sin ver las privadas. Para los que no lo sepáis: en javascript no existe el concepto de &lt;em&gt;variable estática&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La idea que hay detrás del patrón de módulo es muy simple, y como casi siempre pasa simple significa también brillante: Se trata de crear un &lt;em&gt;objeto anónimo&lt;/em&gt;, cuyos campos públicos sean las funciones públicas. Finalmente se crea una instancia de ese objeto y se asigna al namespace &lt;em&gt;global&lt;/em&gt; (eso es, al objeto window).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El código de base sería algo como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(wnd) {&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; miModulo = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; _HazAlgoHelper = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(domObj, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt;) {alert(&lt;span style="color: #006080"&gt;&amp;quot;método privado&amp;quot;&lt;/span&gt;);};&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; _HazAlgo = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(id, &lt;span style="color: #0000ff"&gt;params&lt;/span&gt;, callback) { _HazAlgoHelper(); alert(&lt;span style="color: #006080"&gt;&amp;quot;método público&amp;quot;&lt;/span&gt;}; };&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; {&lt;br /&gt;           HazAlgo : _HazAlgo&lt;br /&gt;        };&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    wnd.m$ = miModulo();&lt;br /&gt;})(window);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien… se que el código puede parecer lioso, la primera vez, pero vamos a analizarlo.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Podemos ver que estamos definiendo una función &lt;strong&gt;anónima&lt;/strong&gt; que acepta un parámetro (llamado &lt;em&gt;wnd&lt;/em&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Y que hace esa función anónima)? Pues para empezar define una variable miModulo que resulta ser… una función (&lt;em&gt;var miModulo = funcion() { …}&lt;/em&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y que hará esa función cuando se invoque? Pues tres cosas:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Definir una variable llamada _HazAlgoHelper… que es &lt;em&gt;otra función&lt;/em&gt;. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Definir una variable llamada _HazAlgo… &lt;em&gt;que es otra función&lt;/em&gt;. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Devolver un objeto anónimo con un campo, llamado HazAlgo. El valor de HazAlgo es el mismo que _HazAlgo (es decir una función). &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Con eso tenemos una función (miModulo) que cuando la invoquemos nos devolverá un objeto con un solo campo (llamado HazAlgo). Así, teoricamente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;miModulo.HazAlgo();    &lt;span style="color: #008000"&gt;// Valido&lt;/span&gt;&lt;br /&gt;miModulo._HazAlgo();   &lt;span style="color: #008000"&gt;// No válido&lt;/span&gt;&lt;br /&gt;miModulo._HazAlgoHelper(); // NO válido&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que la gracia está en que HazAlgo() realmente es lo mismo que _HazAlgo()… y desde _HazAlgo() podemos llamar sin ningún problema a _HazAlgoHelper() que es nuestra función privada. Así la clave es mapear las funciones públicas como campos del objeto anónimo devuelto.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¡Con eso hemos simulado el concepto de funciones privadas!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero, miModulo es una variable local, es local a la función anónima que estamos definiendo. Así que todavía nos queda un paso más: Guardar miModulo en alguna propiedad del parámetro wnd. Eso es lo que hacemos con la línea:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;wnd.m$ = miModulo();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Invocamos miModulo (con parentesis, pues es una función) y guardamos el resultado (el objeto anónimo con el campo HazAlgo) en la propiedad m$ del parámetro wnd.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ya casi estamos… Hasta este punto hemos definido simplemente una función anónima. Ahora toca invocarla. Fijaos en un detalle importante: la primera línea empieza con un paréntesis abierto. Con eso, de hecho, estamos &lt;strong&gt;invocando&lt;/strong&gt; nuestra función anónima. Pero nuestra función anónima espera un parámetro (wnd) así que debemos pasárselo. Eso es lo que hacemos en la última línea: le pasamos window. Y porque window? Pues porque window es un namespace global: todo lo que esté en window es global.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo tanto ahora, desde cualquier parte de mi página puedo hacer:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;script&amp;gt;m$.HazAlgo(1,2,3);&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y eso es correcto, mientras que hacer.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;script&amp;gt;m$._HazAlgoHelper(1,2);&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Nos dará un error.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para tener nuestro módulo listo para ser usado, basta con tenerlo en un .js propio e incluirlo en aquellas páginas donde lo necesitemos. ¡Y listos!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Espero que esto os parezca interesante y os ayude a organizar vuestro código javascript!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como siempre… un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-2013364878969497136?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/2013364878969497136/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=2013364878969497136' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2013364878969497136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2013364878969497136'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/03/htmljs-module-pattern.html' title='[HTML/JS] Module pattern'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-4461453919188659740</id><published>2011-03-15T14:56:00.001+01:00</published><updated>2011-03-15T14:56:52.042+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC: Previsualizar imágenes subidas (2)</title><content type='html'>&lt;p&gt;Buenas! Donde dije digo, digo Diego… Sí, ya sé que dije que el segundo post sería como hacerlo con Ajax, pero bueno… la culpa es de twitter, concretamente de &lt;a href="http://twitter.com/pablonete" target="_blank"&gt;@pablonete&lt;/a&gt; con el que hemos empezado a hablar sobre si es posible evitar el guardar la imágen físicamente en el servidor. Hay un mecanismo obvio, que es usar la sesión (guardar el array de bytes que conforman la imágen en la sesión). Pero… hay otra? Pues sí: usar data urls!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Data urls&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Lo que mucha gente no conoce es que el formato de URL permite &lt;em&gt;incrustar&lt;/em&gt; datos que son &lt;em&gt;interpretados&lt;/em&gt; por el navegador como si se los hubiese descargado externamente. P.ej. la siguiente url es válida:&lt;/p&gt;  &lt;p&gt;data:image/jpeg;base64,xxxxxxx&lt;/p&gt;  &lt;p&gt;donde xxxxxxx es la codificación en base64 de la imágen.&lt;/p&gt;  &lt;p&gt;P.ej. eso es totalmente correcto:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;img&lt;/span&gt; &lt;span style="color: #ff0000"&gt;src&lt;/span&gt;=”&lt;span style="color: #ff0000"&gt;data:image&lt;/span&gt;/&lt;span style="color: #ff0000"&gt;jpeg&lt;/span&gt;;&lt;span style="color: #ff0000"&gt;base64&lt;/span&gt;,&lt;span style="color: #ff0000"&gt;xxxxxx&lt;/span&gt;” &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Veamos como podríamos modificar nuestro proyecto anterior, para usar data urls en lugar de un fichero temporal en el servidor… Fijaos que eso &lt;strong&gt;sólo evita guardar el fichero, la imagen debe ser subida al servidor&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Las modificaciones son muy simples, por un lado primero vamos a modificar la acción del controlador, para que quede así:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[HttpPost]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult SendImage(HttpPostedFileBase img, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; base64, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; contenttype)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (base64 != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; contenttype != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; img==&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #008000"&gt;// Aquí podríamos guardar la imagen (en base64 tenemos los datos)&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&lt;span style="color: #006080"&gt;&amp;quot;Step2&amp;quot;&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    var data = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;byte&lt;/span&gt;[img.ContentLength];&lt;br /&gt;    img.InputStream.Read(data, 0, img.ContentLength);&lt;br /&gt;    var base64Data = Convert.ToBase64String(data);&lt;br /&gt;    ViewBag.ImageData = base64Data;&lt;br /&gt;    ViewBag.ImageContentType = img.ContentType;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La acción recibe tres parámetros:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;img: El fichero seleccionado (contenido del &amp;lt;input type=”file”). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;base64: Codificación en base64 de la imagen &lt;strong&gt;que se está previsualizándo.&lt;/strong&gt; &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;contenttype: Content-type de la imagen &lt;strong&gt;que se está previsualizando.&lt;/strong&gt; &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por supuesto base64 y contenttype sólo se envían si se está previsualizando una imagen. En caso contrario valen null.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijémonos lo que hace la acción, si base64 y contenttype valen null, o bien el usuario ha seleccionado una imagen nueva (img != null):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Obtenemos los datos en base64 de la imagen enviada por el usuario (base64Data). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Pasamos esos datos (junto con el content-type) a la vista, usando el ViewBag. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y la vista que hace? Pues poca cosa:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt; &lt;span style="color: #ff0000"&gt;enctype&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@Url.Action(&amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;SendImage&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Seleccionar imagen:&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;file&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;img&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;br&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    @if (ViewBag.ImageData != null)&lt;br /&gt;    {   &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;img&lt;/span&gt; &lt;span style="color: #ff0000"&gt;src&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;data:@ViewBag.ImageContentType;base64,@ViewBag.ImageData&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;hidden&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@ViewBag.ImageData&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;base64&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;hidden&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@ViewBag.ImageContentType&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;contenttype&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tenemos el formulario con el input type=”submit”, y luego si en el ViewBag vienen los datos de la imagen que se debe previsualizar, genera 3 campos más:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Una imagen, cuyo src es &lt;strong&gt;una data url &lt;/strong&gt;(formato &lt;em&gt;data:content-type;base64,[datos en base64]&lt;/em&gt;) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Dos campos hidden (para guardar el content-type y los datos para mandarlos de vuelta al servidor). &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Con eso tenemos la previsualización de las imágenes &lt;strong&gt;sin necesidad de generar fichero temporal alguno&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finalmente, tres aclaraciones: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Fijaos que la codificación en base64 &lt;strong&gt;se incrusta en la página&lt;/strong&gt; (en este caso se incrusta dos veces, aunque con un poco de javascript podría incrustarse solo una), por lo que esto puede generar páginas &lt;strong&gt;muy grandes&lt;/strong&gt; si la imagen ocupa mucho. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Si no voy errado, los navegadores sólo están obligados a soportar URLs de hasta 1024 bytes. Todo lo que exceda de aquí… depende del navegador. Firefox p.ej. acepta URLs muy largas, pero recordad que Base64 genera fácilmente URLs no muy largas, sinó descomunalmente largas (si la imágen ocupa 100Ks, la URL en Base64 ocupará &lt;strong&gt;más&lt;/strong&gt; de 100Ks). Así que para imágenes pequeñas igual tiene sentido, pero para imágenes largas, honestamente no creo que sea una buena solución. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;La mayoría de navegadores modernos soportan data urls (IE lo empezó a hacer con su versión 8). &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En fin… bueno, como curiosidad no está mal, eh? ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Gracias a &lt;a href="http://twitter.com/pablonete" target="_blank"&gt;Pablo Nuñez&lt;/a&gt; por la divertida e interesante conversación en twitter!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Saludos!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Enlace al post anterior de esa serie: &lt;a href="http://geeks.ms/blogs/etomas/archive/2011/03/15/asp-net-mvc-previsualizar-im-225-genes-subidas-1.aspx" target="_blank"&gt;http://geeks.ms/blogs/etomas/archive/2011/03/15/asp-net-mvc-previsualizar-im-225-genes-subidas-1.aspx&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Otro crosspost des de &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;… &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-4461453919188659740?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/4461453919188659740/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=4461453919188659740' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4461453919188659740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4461453919188659740'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/03/aspnet-mvc-previsualizar-imagenes_15.html' title='ASP.NET MVC: Previsualizar imágenes subidas (2)'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-5366176466386037025</id><published>2011-03-15T10:01:00.001+01:00</published><updated>2011-03-15T10:01:59.204+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC: Previsualizar imágenes subidas (1)</title><content type='html'>&lt;p&gt;Buenas! Una pregunta que últimamente parece que se pregunta varias veces en los foros de ASP.NET MVC es como previsualizar una imagen que se quiere subir al servidor.&lt;/p&gt;  &lt;p&gt;Antes que nada aclarar que, técnicamente, la pregunta está mal hecha: &lt;strong&gt;no es posible previsualizar la imagen &lt;u&gt;antes&lt;/u&gt; de que sea subida&lt;/strong&gt;. Antiguamente en algunos navegadores, y con un poco de javascript, eso era posible, pero ahora por suerte eso ya no funciona :)&lt;/p&gt;  &lt;p&gt;Básicamente &lt;em&gt;previsualizar&lt;/em&gt; una imagen consiste en:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Recibir los datos de la imagen &lt;/li&gt;    &lt;li&gt;Guardarla en algún sitio “temporal” &lt;/li&gt;    &lt;li&gt;Mandarla de &lt;em&gt;vuelta&lt;/em&gt; al navegador &lt;/li&gt;    &lt;li&gt;Borrar la imagen del sitio “temporal” si el usuario no la acepta &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;En este primer post vamos a ver como hacerlo sin usar Ajax. Luego habrá un segundo post y veremos como hacerlo usando Ajax (no es tan sencillo porque XMLHttpRequest no soporta el formato de datos multipart/form-data que es el que se usa cuando se mandan ficheros).&lt;/p&gt;  &lt;p&gt;Bien, vamos a verlo rápidamente, ya veréis cuan sencillo es :)&lt;/p&gt;  &lt;p&gt;Lo primero es tener la vista que tenga el formulario para enviar los datos. La siguiente servirá (si queréis más detalles de como hacer upload de ficheros en MVC mirad &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/09/08/subir-ficheros-al-servidor-en-asp-net-mvc.aspx" target="_blank"&gt;mi post al respecto&lt;/a&gt;):&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Index&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt; &lt;span style="color: #ff0000"&gt;enctype&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@Url.Action(&amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;SendImage&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Seleccionar imagen:&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;file&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;img&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;br&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Trivial: un form con multipart/form-data que enviará sus datos a la acción SendImage. La acción podría ser algo como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[HttpPost]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult SendImage(HttpPostedFileBase img)&lt;br /&gt;{&lt;br /&gt;    var data = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;byte&lt;/span&gt;[img.ContentLength];&lt;br /&gt;    img.InputStream.Read(data, 0, img.ContentLength);&lt;br /&gt;    var path = ControllerContext.HttpContext.Server.MapPath(&lt;span style="color: #006080"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;);&lt;br /&gt;    var filename = Path.Combine(path, Path.GetFileName(img.FileName));&lt;br /&gt;    System.IO.File.WriteAllBytes(Path.Combine(path, filename), data);&lt;br /&gt;    ViewBag.ImageUploaded = filename;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vale, fijaos que recibimos el HttpPostedFileBase (llamado img como el atributo &lt;em&gt;name&lt;/em&gt; del &lt;em&gt;input type=”file”&lt;/em&gt;). Lo que hacemos en la acción es muy simple:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Guardamos la imagen en disco (en este caso por pura pereza uso el directorio raíz de la aplicación web. Por supuesto lo suyo es usar un directorio configurado en web.config y con los permisos NTFS correspondientes). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Coloco en el &lt;em&gt;ViewBag&lt;/em&gt; el nombre de la imagen que se ha guardado (luego vemos porque). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Devuelvo la vista “Index” (la misma de la cual venimos) &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ok, tal y como lo tenemos ahora, si lo probáis veréis que podéis hacer un upload de la imagen, y la imagen se graba en el disco (en el directorio raíz de la aplicación web), pero no se previsualiza nada. Vamos a modificar la vista Index para que haya esa &lt;em&gt;previsualización&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para previsualizar la imagen basta con añadir el siguiente código, despues del &amp;lt;/form&amp;gt; en la vista:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@if (!string.IsNullOrEmpty(ViewBag.ImageUploaded))&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;img&lt;/span&gt; &lt;span style="color: #ff0000"&gt;src&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@Url.Action(&amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;Preview&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot;, new {file=ViewBag.ImageUploaded})&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simple, no? Si en el ViewBag existe la entrada ImageUploaded generamos un tag &amp;lt;img&amp;gt; cuya dirección es la acción “Preview” y le pasamos el parámetro file con el nombre de la imagen. Y como es la acción Preview? Pues super sencilla:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Preview(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; file)&lt;br /&gt;{&lt;br /&gt;    var path = ControllerContext.HttpContext.Server.MapPath(&lt;span style="color: #006080"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (System.IO.File.Exists(Path.Combine(path, file)))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; File(Path.Combine(path, file), &lt;span style="color: #006080"&gt;&amp;quot;image/jpeg&amp;quot;&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpNotFoundResult();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simplemente leemos la imagen guardada y la devolvemos usando un FilePathResult. Simple, eh? ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Con eso, si subís una imagen, cuando le deis a submit, aparecerá de nuevo la vista, pero ahora previsualizando la imagen.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora sólo nos queda el punto final: Que el usuario pueda &lt;em&gt;aceptar&lt;/em&gt; esa imagen como correcta. Para ello lo más simple es hacer lo siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Si el usuario está previsualizando una imagen y NO ha seleccionado otra, cuando hace el submit se entiende que acepta dicha imagen. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Si el usuario NO está previsualizando una imagen, o bien está previsualizando una pero selecciona otra, al hacer el submit se entiende que &lt;em&gt;descarta&lt;/em&gt; la imagen anterior y quiere previsualizar la nueva. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para ello, tenemos que hacer que la vista le indique al controlador &lt;em&gt;si se está previsualizando una imagen, y cual és&lt;/em&gt;. Por suerte eso es muy sencillo. Basta con modificar el &amp;lt;form&amp;gt; de la vista para que su atributo action quede como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;form enctype=&lt;span style="color: #006080"&gt;&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt; method=&lt;span style="color: #006080"&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;br /&gt;action=&lt;span style="color: #006080"&gt;&amp;quot;@Url.Action(&amp;quot;&lt;/span&gt;SendImage&lt;span style="color: #006080"&gt;&amp;quot;, new {previewed=ViewBag.ImageUploaded})&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que añadimos un parámetro &lt;em&gt;previewed&lt;/em&gt; que la vista mandará a la acción y que será el nombre de la imagen que se está previsualizando.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vamos a modificar la acción para que reciba ese parámetro y actúe en consecuencia:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[HttpPost]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult SendImage(HttpPostedFileBase img, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; previewed)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(previewed) &amp;amp;&amp;amp; img == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        ViewBag.ImageName = previewed;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&lt;span style="color: #006080"&gt;&amp;quot;Step2&amp;quot;&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Código tal cual estaba&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Añadimos ese if al inicio: Si el usuario está previsualizando una imagen y no ha seleccionado otra, entendemos que acepta esta imagen. Entonces guardamos el nombre en el ViewBag y lo mandamos a la siguiente vista (Step2).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La vista es muy sencilla:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;h2&amp;gt;Step2&amp;lt;/h2&amp;gt;&lt;br /&gt;&lt;br /&gt;Siguiente paso. El usuario ha aceptado la imagen: &amp;lt;br /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;img src=&lt;span style="color: #006080"&gt;&amp;quot;@Url.Action(&amp;quot;&lt;/span&gt;Preview&lt;span style="color: #006080"&gt;&amp;quot;, new {file=ViewBag.ImageName})&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simplemente mostramos la imagen. Fijaos que de nuevo usamos la acción Preview, puesto que la imagen ya la tenemos guardada en el servidor.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Notas finales&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Faltarían, al menos, dos cosas para que dicho proyecto funcionase “de forma aceptable”:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Borrar las imagenes descartadas por el usuario (en la acción SendImage si se recibe una imagen &lt;em&gt;nueva &lt;/em&gt;y se estaba previsualizando una, borrar esta ya que el usuario la ha descartado). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;La acción&amp;#160; Preview siempre devuelve content-type a image/jpeg, eso debería hacerse según la extensión de la imagen, o guardarlo en algún sitio. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ambas cosas son triviales y no las añado porque lo único que consiguiría es liar el código un poco más ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En el próximo post… lo mismo pero usando Ajax.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Saludos!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Pues sí… otro crosspost de &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog de geeks.ms&lt;/a&gt;! Que raro, no? :P&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-5366176466386037025?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/5366176466386037025/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=5366176466386037025' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5366176466386037025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5366176466386037025'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/03/aspnet-mvc-previsualizar-imagenes.html' title='ASP.NET MVC: Previsualizar imágenes subidas (1)'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8421291299205065823</id><published>2011-02-25T08:55:00.001+01:00</published><updated>2011-02-25T08:55:20.922+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>Rendering de vistas parciales en Razor y MVC3</title><content type='html'>&lt;p&gt;Buenas! Una de las dudas que he visto que se van repitiendo por ahí tiene que ver con &lt;strong&gt;como renderizar vistas parciales en MVC3 usando Razor&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;En MVC2 y anteriores (o en MVC3 usando el ViewEngine de WebForms) la forma de renderizar una vista parcial era sencilla:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;% Html.RenderPartial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;, modelo); %&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mucha gente traduce eso a Razor y usa lo siguiente para renderizar una vista parcial:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@Html.RenderPartial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y se obtiene un error, quizá un poco críptico, que dice lo siguiente: &lt;em&gt;CS1502: The best overloaded method match for 'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)' has some invalid arguments&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El error &lt;strong&gt;no&lt;/strong&gt; está en que Html.RenderPartial no pueda usarse con Razor, el error está en la sintaxis que estamos usando. Cuando en Razor usamos la @ para indicar el inicio de código de servidor, la expresión que viene a continuación &lt;strong&gt;debe devolver un valor&lt;/strong&gt;, que será incluído en la respuesta a enviar al navegador. La excepción a esa norma es cuando lo que sigue a la @ es una palabra clave reservada de Razor (como @model) o una palabra clave reservada del lenguaje que estemos usando (como @foreach). Esos casos especiales Razor los sabe tratar y actúa en consecuencia. Pero en el resto de casos &lt;strong&gt;siempre, siempre, siempre la expresión debe devolver un valor&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Hablando en términos del engine de WebForms, el código Razor:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@Html.RenderPartial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;, modelo)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Se corresponde a:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;%: Html.RenderPartial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;,modelo) %&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Que es erróneo (y da el error &lt;em&gt;CS1502: The best overloaded method match for 'System.Web.HttpUtility.HtmlEncode(string)' has some invalid arguments&lt;/em&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Entonces… como usar Html.RenderPartial en Razor? Fácil: usando llaves para indicarle al motor de Razor que eso es un código que debe ejecutar, en lugar de un valor que debe incrustar en la respuesta:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@{ Html.RenderPartial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;); }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues: Html.RenderPartial &lt;em&gt;puede&lt;/em&gt; usarse en Razor sin ningún problema… como el resto de Helpers que conozcáis. Si el método lo usábais con &amp;lt;% … %&amp;gt; en Razor es @{ … }, mientras que si usábais &amp;lt;%: … %&amp;gt; en Razor es simplemente @…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Otras maneras de incrustar vistas parciales &lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De todas formas hay un par de métodos más para incrustar vistas parciales.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El primer método es &lt;strong&gt;Html.Partial()&lt;/strong&gt; un método de extensión adicional. Para llamarlo se usan los mismos parámetros que Html.RenderPartial. La diferencia es que Html.Partial devuelve una IHtmlString con los contenidos de la vista renderizada. Por lo tanto, para incrustar una vista usando Html.Partial() usamos:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// Razor&lt;/span&gt;&lt;br /&gt;@Html.Partial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #008000"&gt;// Webforms viewengine&lt;/span&gt;&lt;br /&gt;&amp;lt;%: Html.Partial(&lt;span style="color: #006080"&gt;&amp;quot;VistaParcial&amp;quot;&lt;/span&gt;) %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El segundo método es propio de Razor, ya que está definido dentro del framework que se conoce como “WebPages” y es usar el método RenderPage, definido en la clase WebPageBase de la cual heredan las vistas Razor.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Dicho método acepta dos parámetros:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;La localización de la vista. Ojo! No el nombre, sinó su localización (incluyendo directorios) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Parámetros a pasar a la vista (params object[]). &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;P.ej. para renderizar la vista parcial usaríamos:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@RenderPage(&lt;span style="color: #006080"&gt;&amp;quot;~/Views/Home/VistaParcial.cshtml&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en que se debe usar el nombre del archivo de la vista a incluir (incluyendo extensión .cshtml).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si se pasan parámetros a la vista parcial, estos &lt;strong&gt;no&lt;/strong&gt; están disponibles usando la propiedad Model en la vista, sinó que debe usarse la propiedad &lt;em&gt;PageData&lt;/em&gt;. P.ej. podríamos pasar una cadena y un entero a la vista:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@RenderPage(&lt;span style="color: #006080"&gt;&amp;quot;~/Views/Home/VistaParcial.cshtml&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;Parametro 1&amp;quot;&lt;/span&gt;, 10)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y mostrarlos desde la vista con el uso de PageData:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@foreach (var item in PageData)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;@item.Value&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mi opinión sobre el método RenderPage (en MVC): Sobra totalmente, y espero que nunca, nunca, nunca lo uséis. Porque? Pues porque RenderPage &lt;strong&gt;rompe&lt;/strong&gt; la encapsulación del framework (en lugar de especificar un &lt;em&gt;nombre&lt;/em&gt; de vista debéis especificar un &lt;em&gt;fichero&lt;/em&gt;). Es evidente que existe para dar soporte a WebPages pero WebPages y MVC se parecen sólo porque usan Razor como sintaxis, pero en concepción son dos cosas totalmente distintas… Aunque por razones (supongo que técnicas) Razor depende de WebPages y esa dependencia se arrastra a MVC3, cosa que personalmente no me gusta demasiado. Pero es lo hay… ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Conclusiones&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Html.RenderPartial funciona correctamente en Razor, al igual que el resto de métodos de &lt;em&gt;siempre&lt;/em&gt;. Sólo debemos tener cuidado en usar la sintaxis correcta. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Html.Partial es un método adicional para renderizar vistas parciales. La diferencia con Html.RenderPartial() es que este último escribe en la response directamente el contenido de la vista, mientras que Partial() lo devuelve dentro de una cadena. No tengo claras las implicaciones de rendimiento que puede tener empezar a crear mutltiud de cadenas que serán eliminadas por el GC casi de inmediato. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;RenderPage es el método de WebPages para renderizar vistas parciales. Desde el punto de vista de MVC es un método que sobra totalmente y que rompe la encapsulación del framework. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Espero que os sea útil!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8421291299205065823?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8421291299205065823/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8421291299205065823' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8421291299205065823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8421291299205065823'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/02/rendering-de-vistas-parciales-en-razor.html' title='Rendering de vistas parciales en Razor y MVC3'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-1721705252978449250</id><published>2011-02-17T20:38:00.001+01:00</published><updated>2011-02-17T20:38:32.955+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><title type='text'>De los requerimientos…</title><content type='html'>&lt;p&gt;Mi hermano y yo ambos somos arquitectos. Aunque en su caso él tiene un título universitario que lo acredita como tal y yo sólo una tarjeta de trabajo donde mi empresa ha decidido poner eso… y en inglés que se supone que queda mejor. Los dos nos dedicamos a &lt;em&gt;pensar y diseñar&lt;/em&gt; cosas: él piensa y diseña espacios habitables (o sea pisos y casas) y yo pienso y diseño soluciones informáticas (o sea programas).&lt;/p&gt;  &lt;p&gt;Ayer mi hermano (que no sólo es arquitecto, sinó que regenta una empresa de obras) me vino riéndose por una petición de presupuesto en broma que había recibido. El correo electrónico decía, más o menos, así…&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Apreciado hermano de eiximenis,&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#646b86"&gt;&lt;em&gt;Nos dirigimos a Ud. para que nos haga un presupuesto para la construcción de una nueva mansión para un concejal cualquiera (a partir de ahora “el cliente”) que, con un golpe de fortuna, ha ganado unos dinerillos que gastar&lt;/em&gt;. &lt;em&gt;A continuación le detallamos como debe la mansión:&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;La mansión contará con el número de habitaciones que el cliente estime cómo necesarias para el desarrollo de sus funciones de descanso y/o copulación. Además el cliente debe poder realizar otras funciones (a especificar en algún momento del futuro) sin menoscabo de la comodidad mínima exigida.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Los materiales de construcción deben tener el nivel de calidad requerido por el cliente, nivel que por supuesto no aparece en ningún estándard y que sólo el cliente conoce y que puede variar en función de su estado de ánimo.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Deberán integrarse, adaptarse o construirse distintos módulos de diversión, para aquellas actividades de ocio que el cliente considere necesarias. No es necesario especificar que las necesidades de ocio del cliente pueden variar en cualquier momento durante el periodo de tres años que se exige como mantenimiento.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;El número de baños deberá ser el justo y necesario para que pueda usarlos el cliente, así como los invitados a sus fiestas. El número de invitados no ha sido proporcionado por el cliente.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Se valorará positivamente que los garajes estén listos al cabo de dos semanas y más positivamente si lo están al cabo de una.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;El cliente ha comprado un módulo de domótica que deberá ser instalado y configurado. El modelo es desconocido al igual que el fabricante.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Existe un periodo de tres años de garantía, donde el cliente puede solicitar cambios en los materiales, disposición de los módulos, módulos de ocio nuevos, etc, etc&lt;/font&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Dado que el cliente es un concejal debe asignar la obra de forma totalmente legal y por ello se deberán entregar tres sobres:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;El primero con la propuesta económica final. Dicha propuesta contendrá el precio exacto de la obra, incluyendo materiales y mano de obra y mantenimiento durante los 3 años. El mantenimiento implica adaptar la mansión a las nuevas necesidades que le puedan surgir al cliente. Hay total libertad de precio, siempre que no pase de 500000€&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;El segundo con el calendario exacto de las obras: cuando estará el garaje, las distintas habitaciones, la fachada principal, los módulos de ocio, etc. El inclumpimiento del calendario acarreará sanciones económicas a determinar.&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;El tercero con los detalles técnicos, planos de obra, materiales usados, etc&lt;/font&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;em&gt;&lt;font color="#646b86"&gt;La valoración por concurso será tal y como sigue:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Valoración económica: Un 50% (De 0 a 5 puntos)&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Calendario: Un 40% (de 0 a 4 puntos)&lt;/font&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Detalles técnicos: Un 10% (de 0 a 1 punto)&lt;/font&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;em&gt;&lt;font color="#646b86"&gt;Se pide envío de los tres sobres antes de 2 días. El cliente no está disponible para contactar ya que está de vacaciones.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Mi hermano entre carcajadas y carcajada, me insistía en que le viera la gracia a la broma, que si “fíjate que aquí no concretan nada, que si eso es buenísimo porque ni dicen el número de las habitaciones, en que si tal y cual”…&lt;/p&gt;  &lt;p&gt;… yo, la verdad es que sonreí un poco por compromiso mientras por dentro pensaba en las muchas veces que mi trabajo parece una broma… y de mal gusto.&lt;/p&gt;  &lt;p&gt;Saludos!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-1721705252978449250?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/1721705252978449250/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=1721705252978449250' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1721705252978449250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1721705252978449250'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/02/de-los-requerimientos.html' title='De los requerimientos…'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-6768298696498505051</id><published>2011-02-08T08:53:00.001+01:00</published><updated>2011-02-08T08:53:17.481+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>[Material] WebCast ASP.NET MVC</title><content type='html'>&lt;p&gt;Buenas.&lt;/p&gt;  &lt;p&gt;Este post simplemente es para agradeceros a todos el interés que mostrasteis en el &lt;a href="http://geeks.ms/blogs/etomas/archive/2011/02/02/webcast-191-te-quedaste-con-m-225-s-ganas-asp-net-mvc-ii.aspx" target="_blank"&gt;Webcast de ASP.NET MVC que tuve el placer de realizar&lt;/a&gt; para la gente del &lt;a href="http://lleida.dotnetclubs.com/" target="_blank"&gt;Lledia DotNetClub&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Antes que nada os dejo la página desde donde os podéis ver o descargaros el WebCast: &lt;a title="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=es-ES&amp;amp;EventID=1032476809&amp;amp;CountryCode=ES" href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=es-ES&amp;amp;EventID=1032476809&amp;amp;CountryCode=ES"&gt;https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=es-ES&amp;amp;EventID=1032476809&amp;amp;CountryCode=ES&lt;/a&gt;. En esa página veréis un enlace que pone “&lt;em&gt;Regístrese sin cuenta de Windows Live ID&lt;/em&gt;” que es el que os llevará a la página de descarga.&lt;/p&gt;  &lt;p&gt;Increíble, eh? Esta vez no la pifié con el livemeeting y quedó grabado! :)&lt;/p&gt;  &lt;p&gt;Os dejo:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;El código fuente de Porrazo completo. Porrazo, el sistema de porras on-line, fue lo que más o menos fuimos desarrollando a lo largo de los dos webcasts. En el código veréis implementadas todas las técnicas de las que hablamos (con la excepción del helper WebGrid). Por supuesto que Porrazo es un conglomerado de técnicas de hacer las cosas: no significa que todas deban implementarse en una misma aplicación MVC. A vosotros os toca juzgar en cada caso cual es la mejor opción! &lt;/li&gt;    &lt;li&gt;Los dos ppts, aunqué no tienen apenas información, ya que son un mero índice. &lt;/li&gt;    &lt;li&gt;El script SQL para crear las tablas (sin datos… los datos deberéis ponerlos vosotros… :p). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Lo tenéis en: &lt;a title="http://cid-6521c259e9b1bec6.office.live.com/browse.aspx/BurbujasNet/ZipsPosts/Porrazo" href="http://cid-6521c259e9b1bec6.office.live.com/browse.aspx/BurbujasNet/ZipsPosts/Porrazo"&gt;http://cid-6521c259e9b1bec6.office.live.com/browse.aspx/BurbujasNet/ZipsPosts/Porrazo&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;En breve me gustaría hacer un documento word (en esa misma carpeta) para que podáis realizar step-by-step Porrazo desde cero y podáis practicar las técnicas que vimos. Pero como ello me va a llevar cierto tiempo, prefiero dejaros los fuentes ya disponibles, y actualizar este post cuando tenga el documento realizado.&lt;/p&gt;  &lt;p&gt;Si alquien quiere que le avise personalmente cuando tenga el documento, puede enviarme un mail (mi correo está en los ppts) o contactar conmigo a través del formulario de contacto del blog.&lt;/p&gt;  &lt;p&gt;Muchas gracias!&lt;/p&gt;  &lt;p&gt;PD: Eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog en geeks.ms!&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-6768298696498505051?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/6768298696498505051/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=6768298696498505051' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6768298696498505051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6768298696498505051'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/02/material-webcast-aspnet-mvc.html' title='[Material] WebCast ASP.NET MVC'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-5794272679233259624</id><published>2011-02-02T10:20:00.001+01:00</published><updated>2011-02-02T10:20:32.482+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>[WebCast] ¿Te quedaste con más ganas? ASP.NET MVC II</title><content type='html'>&lt;p&gt;Muy buenas! Este jueves &lt;strong&gt;03 de febrero&lt;/strong&gt; (o sea mañana) gracias a la gente del &lt;a href="http://lleida.dotnetclubs.com/" target="_blank"&gt;Lleida dotnet club&lt;/a&gt;, tengo el gusto de dar un WebCast sobre ASP.NET MVC :)&lt;/p&gt;  &lt;p&gt;La verdad es que el WebCast está pensado para ser la continuación del que &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/12/01/evento-recordatorio-este-jueves-hasta-d-243-nde-podemos-llegar-con-asp-net-mvc.aspx" target="_blank"&gt;dí el pasado 2 de&lt;/a&gt; diciembre. En aquel webcast vimos:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Introducción a ASP.NET MVC &lt;/li&gt;    &lt;li&gt;Membership providers para autenticación y autorización &lt;/li&gt;    &lt;li&gt;Uso de Unity para desacoplar dependencias &lt;/li&gt;    &lt;li&gt;El patrón repositorio para acceder a la BBDD &lt;/li&gt;    &lt;li&gt;Uso de Ajax con Json &lt;/li&gt;    &lt;li&gt;Templates con jquery-tmpl &lt;/li&gt;    &lt;li&gt;Binding de datos en los controladores &lt;/li&gt;    &lt;li&gt;Guardando datos en la bbdd: Unit of Work &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Todo ello lo vimos desarrollando una aplicación desde cero (al que mi departamento de marketing llamó &lt;em&gt;Porrazo&lt;/em&gt;), y este nuevo webcast continuará donde se quedó aquel. Lamentablemente, debido a que soy un negado en eso del livemeeting el webcast no quedó grabado, así que al principio vamos a dar un rápido resumen a lo visto en aquel webcast, para que estemos todos en situación… Y luego proseguiremos con los puntos que se nos quedaron en el tintero:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Uso de un Role Provider &lt;/li&gt;    &lt;li&gt;Añadiendo un módulo de administración (áreas) &lt;/li&gt;    &lt;li&gt;Componiendo presentación (uso de vistas parciales) &lt;/li&gt;    &lt;li&gt;Grids!! (Sí… esa es una &lt;em&gt;feature&lt;/em&gt; que la gente pide mucho) &lt;/li&gt;    &lt;li&gt;Ventanas flotantes (popups) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Si me da tiempo (espero no volver a enrollarme) veremos algunos temas addicionales como:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Validación de datos en cliente &lt;/li&gt;    &lt;li&gt;Unobtrusive javascript &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Y al final una sesión de preguntas y respuestas (pero… no os paséis: que sean facilitas, eh? ;-))&lt;/p&gt;  &lt;p&gt;Todo ello con ASP.NET MVC3, con VS2010 a tope (nada de power points!) y desarrollando Porrazo, el sistema de porras online que cuando esté finalizado colgaré aquí con la esperanza de que lo compre Google y me retire.&lt;/p&gt;  &lt;p&gt;La &lt;a href="https://msevents.microsoft.com/CUI/Register.aspx?culture=es-ES&amp;amp;EventID=1032476808&amp;amp;CountryCode=ES&amp;amp;IsRedirect=false" target="_blank"&gt;página de registro&lt;/a&gt; esá en: &lt;a title="https://msevents.microsoft.com/CUI/Register.aspx?culture=es-ES&amp;amp;EventID=1032476808&amp;amp;CountryCode=ES&amp;amp;IsRedirect=false" href="https://msevents.microsoft.com/CUI/Register.aspx?culture=es-ES&amp;amp;EventID=1032476808&amp;amp;CountryCode=ES&amp;amp;IsRedirect=false"&gt;https://msevents.microsoft.com/CUI/Register.aspx?culture=es-ES&amp;amp;EventID=1032476808&amp;amp;CountryCode=ES&amp;amp;IsRedirect=false&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Un saludo a todos!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-5794272679233259624?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/5794272679233259624/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=5794272679233259624' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5794272679233259624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5794272679233259624'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/02/webcast-te-quedaste-con-mas-ganas.html' title='[WebCast] ¿Te quedaste con más ganas? ASP.NET MVC II'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-947810603506467915</id><published>2011-01-26T09:37:00.001+01:00</published><updated>2011-01-26T09:37:06.310+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC3: Un helper Repeater</title><content type='html'>&lt;p&gt;Muy buenas! En el post anterior comenté la característica de los &lt;a href="http://geeks.ms/blogs/etomas/archive/2011/01/25/asp-net-mvc3-razor-templates.aspx" target="_blank"&gt;templates de Razor&lt;/a&gt; y hoy vamos a ver como podríamos crear un &lt;em&gt;helper&lt;/em&gt; que emule un poco el &lt;a href="http://msdn.microsoft.com/es-es/library/6weyd81h(VS.80).aspx" target="_blank"&gt;control Repeater&lt;/a&gt; que hay en webforms (salvando las distancias, claro).&lt;/p&gt;  &lt;p&gt;Vamos a crear un &lt;em&gt;helper externo&lt;/em&gt;, es decir que sea reutilizable en distintos proyectos: para ello nuestro helper va a residir en una clase (en mi ejemplo en el propio proyecto web, pero se podría situar en una librería de clases para ser reutilizable).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Esqueleto inicial&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A nuestro helper se le pasará lo siguiente:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Una cabecera: template Razor que se renderizará una sola vez al principio. &lt;/li&gt;    &lt;li&gt;Un cuerpo: template Razor que se renderizará una vez por cada elemento &lt;/li&gt;    &lt;li&gt;Un pie: template Razor que se renderizará una sola vez al final. &lt;/li&gt;    &lt;li&gt;Una colección de elementos (por cada elemento se renderizará el cuerpo). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Recordáis que ayer comentamos que los templates Razor son Func&amp;lt;T, HelperResult&amp;gt;? &lt;/p&gt;  &lt;p&gt;Bien, pues vamos a declarar nuestro helper:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IHtmlString Repeat&amp;lt;TItem&amp;gt;(&lt;br /&gt;    IEnumerable&amp;lt;TItem&amp;gt; items,&lt;br /&gt;    Func&amp;lt;dynamic, HelperResult&amp;gt; header,&lt;br /&gt;    Func&amp;lt;TItem, HelperResult&amp;gt; body,&lt;br /&gt;    Func&amp;lt;dynamic, HelperResult&amp;gt; footer&lt;br /&gt;    )&lt;br /&gt;{&lt;br /&gt;    var builder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (header != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        builder.Append(header(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;).ToHtmlString());&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; items)&lt;br /&gt;    {&lt;br /&gt;        builder.Append(body(item).ToHtmlString());&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (footer != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        builder.Append(footer(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;).ToHtmlString());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; MvcHtmlString.Create(builder.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Los templates siempre están declarados como Func&amp;lt;T, HelperResult&amp;gt;, en este caso declaramos tres templates:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;header, cuyo parámetro @item es dynamic. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;body, cuyo parámetro @item es TItem, donde TItem es el tipo del enumerable que se le pasa al helper &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;footer, cuyo parámetro @item es dynamic &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para invocar los templates y obtener el html asociado simplemente invocamos el Func (pasándole el parámetro del tipo correcto) y sobre el resultado llamamos a &lt;strong&gt;ToHtmlString&lt;/strong&gt;: Este método nos devuelve la cadena HTML que ha parseado Razor.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora p.ej. me creo una acción tal en el controlador:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult List()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Product&amp;gt;&lt;br /&gt;                    {&lt;br /&gt;                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Product() {Nombre=&lt;span style="color: #006080"&gt;&amp;quot;PS3&amp;quot;&lt;/span&gt;, Precio=300},&lt;br /&gt;                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Product() {Nombre=&lt;span style="color: #006080"&gt;&amp;quot;XBox360&amp;quot;&lt;/span&gt;, Precio=150},&lt;br /&gt;                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Product() {Nombre=&lt;span style="color: #006080"&gt;&amp;quot;Wii&amp;quot;&lt;/span&gt;, Precio=100}&lt;br /&gt;                    });&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y en la vista asociada:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@using MvcApplication14.Helpers&lt;br /&gt;@model IEnumerable&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;MvcApplication14.Models.Product&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;table&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;@Repeater.Repeat(Model, &lt;br /&gt;    @&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Nombre&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Precio&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;, &lt;br /&gt;    @&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;@item.Nombre&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;@item.Precio&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;, &lt;br /&gt;    null)&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;table&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en la llamada a Repeater.Repeat, donde le paso el modelo que recibe la vista (que es un IEnumerable de Product) y los tres templates Razor (en este caso no le paso footer y por ello pongo null).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En el segundo template (body) puedo acceder al elemento que se está renderizando mediante @item. Además, dado que en helper he declarado el template body de tipo Func&amp;lt;TItem, HelperResult&amp;gt;, tengo soporte de Intellisense:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_1JRa_Jfnm20/TT_dKk0h20I/AAAAAAAAEJI/86HJSGr889U/s1600-h/image%5B2%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_1JRa_Jfnm20/TT_dLLXDGaI/AAAAAAAAEJM/_0P2YtqD9eE/image_thumb.png?imgmax=800" width="244" height="107" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si teclease @item en el template header o footer no tendría intellisense porque los he declarado dynamic en el helper (además ojo, que en el helper le paso null, por lo que rebentaría si usamos @item en el template header o footer).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! El código HTML generado es:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Nombre&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Precio&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;PS3&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;300&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;XBox360&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;150&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Wii&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;100&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Guay, no?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Podríamos “complicar” un poco el helper, para que desde los templates supiesemos si estamos en una fila par o impar y así aplicar clases… Para ello nos basta con declarar una clase adicional en nuestor helper:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RepeaterItem&amp;lt;TItem&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Index { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set; }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsEven { get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Index % 2 == 0; } }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TItem Item { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RepeaterItem(TItem item, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; index)&lt;br /&gt;    {&lt;br /&gt;        Index = index;&lt;br /&gt;        Item = item;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Esa clase simplemente contiene el índice del elemento actual, el propio elemento y una propiedad que indica si es par o no.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora modificamos el helper para pasarle al template body un objeto RepeaterItem&amp;lt;TItem&amp;gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repeater&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IHtmlString Repeat&amp;lt;TItem&amp;gt;(&lt;br /&gt;        IEnumerable&amp;lt;TItem&amp;gt; items,&lt;br /&gt;        Func&amp;lt;dynamic, HelperResult&amp;gt; header,&lt;br /&gt;        Func&amp;lt;RepeaterItem&amp;lt;TItem&amp;gt;, HelperResult&amp;gt; body,&lt;br /&gt;        Func&amp;lt;dynamic, HelperResult&amp;gt; footer&lt;br /&gt;        )&lt;br /&gt;    {&lt;br /&gt;        var builder = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (header != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            builder.Append(header(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;).ToHtmlString());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        var count = 0;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; items)&lt;br /&gt;        {&lt;br /&gt;            var repeaterItem = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RepeaterItem&amp;lt;TItem&amp;gt;(item, count++);&lt;br /&gt;            builder.Append(body(repeaterItem).ToHtmlString());&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (footer != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            builder.Append(footer(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;).ToHtmlString());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; MvcHtmlString.Create(builder.ToString());&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Los cambios básicamente son declarar el template domo Func&amp;lt;RepeaterItem&amp;lt;Titem&amp;gt;&amp;gt; y cuando invocamos el template, crear antes un objeto RepeaterItem y pasárselo como parámetro.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finalmente ahora debemos modificar la vista, ya que el parámetro @item de nuestro template es ahora un RepeaterItem&amp;lt;TItem&amp;gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@Repeater.Repeat(Model, &lt;br /&gt;    @&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Nombre&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Precio&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;thead&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;, &lt;br /&gt;    @&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt; &lt;span style="color: #ff0000"&gt;style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@(item.IsEven ? &amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;background-color:&lt;/span&gt; &lt;span style="color: #ff0000"&gt;white&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot; : &amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;background-color:pink&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;@item.Item.Nombre&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;@item.Item.Precio&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;td&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;tr&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;, &lt;br /&gt;    null)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos como dentro del template body puedo preguntar si el elemento actual es par (@item.IsEven y acceder al propio elemento @item.Item). En este caso uso @item.IsEven para cambiar el color de fondo de la fila:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_1JRa_Jfnm20/TT_dLp0Y0II/AAAAAAAAEJQ/zhS_-2k_pP4/s1600-h/image%5B5%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_1JRa_Jfnm20/TT_dMbanAeI/AAAAAAAAEJU/kLoAqFt4vEY/image_thumb%5B1%5D.png?imgmax=800" width="145" height="133" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Espero que esos dos posts sobre templates Razor os hayan parecido interesantes! &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo a todos! ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como siempre… eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-947810603506467915?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/947810603506467915/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=947810603506467915' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/947810603506467915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/947810603506467915'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc3-un-helper-repeater.html' title='ASP.NET MVC3: Un helper Repeater'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_1JRa_Jfnm20/TT_dLLXDGaI/AAAAAAAAEJM/_0P2YtqD9eE/s72-c/image_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-6262487405996663067</id><published>2011-01-25T16:41:00.001+01:00</published><updated>2011-01-25T16:41:15.814+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC3: Razor Templates</title><content type='html'>&lt;p&gt;Muy buenas!&lt;/p&gt;  &lt;p&gt;En este post quiero comentaros una característica de Razor que yo considero que es una &lt;strong&gt;&lt;u&gt;auténtica pasada:&lt;/u&gt;&lt;/strong&gt; los &lt;strong&gt;templates&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Básicamente &lt;strong&gt;el meollo de todo está en la posibilidad de guardar el resultado de un parseo de Razor en un Func&amp;lt;T, HelperResult&amp;gt;&lt;/strong&gt; siendo T el tipo del modelo que renderiza el template.&lt;/p&gt;  &lt;p&gt;Veámoslo con código:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@{&lt;br /&gt;    Func&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;string&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;HelperResult&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; h =&lt;br /&gt;        @&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Esto es un template al que se le han pasado los datos: @item&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    ;&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     Renderizamos el template: @h(&amp;quot;datos&amp;quot;)&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos como nos guardamos en una Func&amp;lt;string, HelperResult&amp;gt; el resultado de renderizar un template razor (en este caso el template &amp;lt;h2&amp;gt;…&amp;lt;/h2&amp;gt;). Fijaos en tres detalles:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Dado que la variable h está declarada como Func&amp;lt;string, HelperResult&amp;gt; el tipo del modelo en este template es “string” &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Para acceder al modelo que se pasa al template se usa @item &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Al final del template Razor ponemos un ; (eso es una declaración C# y como tal &lt;em&gt;debe&lt;/em&gt; terminar en punto y coma). &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Luego más adelante renderizamos el template, con el código: @h(&amp;quot;datos&amp;quot;)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;strong&gt;Eh!! Eso no es lo mismo que @helper?&lt;/strong&gt;&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si conoces @helper te puede parecer que esto no es muy novedoso. Con @helper podemos crear helpers inline de la siguiente manera:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@helper h2(string s) {&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Esto es un helper: @s&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y lo podíamos invocar con:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@h2(&amp;quot;ufo&amp;quot;)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo que parece que viene a ser lo mismo. Y es que, en el fondo, ambas construcciones devuelven un HelperResult. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;p&gt;&lt;strong&gt;Nota: &lt;/strong&gt;Si quieres más información sobre @helper, léete el post que hizo el maestro hace algún tiempecillo: &lt;a title="http://www.variablenotfound.com/2010/11/y-mas-sobre-helpers-en-razor.html" href="http://www.variablenotfound.com/2010/11/y-mas-sobre-helpers-en-razor.html"&gt;http://www.variablenotfound.com/2010/11/y-mas-sobre-helpers-en-razor.html&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lo interesante no es que ambas construccione se parezcan, lo que quiero recalcar es que…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;… Los templates son Func&amp;lt;T, HelperResult&amp;gt;!&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lo pongo así en negrita porque eso es importante, y a la vez me sirve de título. Si los templates Razor son Func&amp;lt;T, HelperResult&amp;gt;… &lt;em&gt;cualquier método que reciba un Fun&amp;lt;T, HelperResult&amp;gt; puede recibir un template Razor&lt;/em&gt;…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;… Incluídos los helpers!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@helper Repeater(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; count,Func&amp;lt;dynamic, HelperResult&amp;gt; template, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; data) {&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;    @&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; idx=0; idx&amp;lt;count; idx++)&lt;br /&gt;    {&lt;br /&gt;        &amp;lt;li&amp;gt;@template(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; { Text = data, Index = idx })&amp;lt;/li&amp;gt;&lt;br /&gt;    }&lt;br /&gt;    &amp;lt;/ul&amp;gt;   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Repeater(10, @&amp;lt;span&amp;gt;@item.Text (item: #@item.Index)&amp;lt;/span&amp;gt;, &lt;span style="color: #006080"&gt;&amp;quot;Ufo&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Declaramos un helper, llamado Repeater que acepta tres parámetros: &lt;br /&gt;    &lt;ol&gt;&lt;br /&gt;      &lt;li&gt;Un entero &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;      &lt;li&gt;Un Func&amp;lt;dynamic, HelperResult&amp;gt; que &lt;em&gt;por lo tanto podrá ser un template Razor&lt;/em&gt; &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;      &lt;li&gt;Una cadena &lt;/li&gt;&lt;br /&gt;    &lt;/ol&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;El helper se limita a crear una lista y luego: &lt;br /&gt;    &lt;ol&gt;&lt;br /&gt;      &lt;li&gt;Crea tantos &amp;lt;li&amp;gt; como indica el paràmetro count y en cada id &lt;br /&gt;        &lt;ol&gt;&lt;br /&gt;          &lt;li&gt;Evalúa el segundo parámetro &lt;em&gt;(que es el Func) y le pasa como parámetro un objeto anonimo con dos propiedades (Text e Index), donde Text es el tercer parámetro que recibe (y index el valor de la iteración actual&lt;/em&gt;). &lt;/li&gt;&lt;br /&gt;        &lt;/ol&gt;&lt;br /&gt;      &lt;/li&gt;&lt;br /&gt;    &lt;/ol&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Cuando invocamos al helper, le pasamos como primer parámetro el número de repeticiones, como segundo parámetro &lt;strong&gt;un template de Razor&lt;/strong&gt;. Fijaos que dentro de dicho template: &lt;br /&gt;&lt;br /&gt;    &lt;ol&gt;&lt;br /&gt;      &lt;li&gt;Accedemos a las propiedades @item.Text y @item.Index. Eso podemos hacerlo porque hemos declarado el tipo del modelo de dicho template como &lt;em&gt;dynamic&lt;/em&gt; y por eso nos compila (y nos funciona porque el helper cuando invoca el template crea esas propiedades en el objeto anónimo). &lt;/li&gt;&lt;br /&gt;    &lt;/ol&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El código HTML generado por dicha llamada al helper Repeater es:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ul&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #0)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #1)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #2)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #3)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #4)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #5)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #6)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #7)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #8)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Ufo (item: #9)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;span&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ul&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Espero que el post os haya resultado interesante!!! ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Saludos!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como siempre… otro crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-6262487405996663067?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/6262487405996663067/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=6262487405996663067' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6262487405996663067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6262487405996663067'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc3-razor-templates.html' title='ASP.NET MVC3: Razor Templates'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-833941082571888138</id><published>2011-01-19T11:07:00.001+01:00</published><updated>2011-01-19T11:07:27.509+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC: Como recuperar un dato de una cookie para cada petición… Una alternativa ¿igual?</title><content type='html'>&lt;p&gt;Muy buenas! Hace algunos días escribí el post &lt;a href="http://geeks.ms/blogs/etomas/archive/2011/01/14/asp-net-mvc-como-recuperar-un-dato-de-una-cookie-para-cada-petici-243-n.aspx" target="_blank"&gt;ASP.NET MVC: Como recuperar datos de una cookie en cada petición&lt;/a&gt;, donde mostraba el uso de un &lt;em&gt;route handler&lt;/em&gt; propio para recuperar los datos de una cookie y colocarlos en el Route Data. En el ejemplo era una cookie de cultura de la aplicación, pero se puede aplicar a lo que queráis.&lt;/p&gt;  &lt;p&gt;Lo que más me gusta de ASP.NET MVC es que muy expandible, que muchas cosas pueden hacerse de más de una forma. Pues bien, una de las novedades más interesantes de MVC3 (al margen de Razor) son los action filters &lt;strong&gt;globales&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;En este post os propongo una &lt;strong&gt;solución alternativa &lt;/strong&gt;(aunque ya veremos que tiene una &lt;em&gt;ligerísima&lt;/em&gt; diferencia) al mismo problema. La diferencia es que &lt;strong&gt;no se debe alterar la tabla de rutas para nada&lt;/strong&gt;. Y dicha solución pasa por usar un action filter global.&lt;/p&gt;  &lt;p&gt;Una de las cosas que en MVC nos debe quedar claro es que &lt;em&gt;cuando repitamos muchas veces un mismo código&lt;/em&gt; &lt;em&gt;de un controlador &lt;/em&gt;debemos considerar de ponerlo en un Action Filter. El “problema” está que los action filters deben aplicarse controlador a controlador (o acción a acción). Si tenemos un filtro que debe aplicarse a todos los controladores podemos considerar crear una clase base que lo tenga y heredar todos los controladores de ella…&lt;/p&gt;  &lt;p&gt;… o al menos eso era así &lt;em&gt;antes&lt;/em&gt; de MVC3.&lt;/p&gt;  &lt;p&gt;Con MVC3 y los filtros globales podemos aplicar un filtro &lt;em&gt;a todas las acciones de todos los controladores&lt;/em&gt;. Y todo ello con &lt;strong&gt;una sola línea en global.asax. &lt;/strong&gt;Es brutal!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;El filtro global…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Lo bueno es que los filtros globales &lt;strong&gt;se implementan igual&lt;/strong&gt; que los filtros no globales clásicos que teníamos en MVC2. En este caso la implementación es super sencilla:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CookieCultureFilterAttribute : ActionFilterAttribute&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnActionExecuting(ActionExecutingContext filterContext)&lt;br /&gt;    {&lt;br /&gt;        var cultureCookieVal = GetCultureFromCookie(filterContext.HttpContext.Request.Cookies);&lt;br /&gt;        var culture = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CultureInfo(cultureCookieVal);&lt;br /&gt;        filterContext.RouteData.Values.Add(&lt;span style="color: #006080"&gt;&amp;quot;culture&amp;quot;&lt;/span&gt;, cultureCookieVal);&lt;br /&gt;        Thread.CurrentThread.CurrentCulture = culture;&lt;br /&gt;        Thread.CurrentThread.CurrentUICulture = culture;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; GetCultureFromCookie(HttpCookieCollection cookies)&lt;br /&gt;    {&lt;br /&gt;        var retValue = &lt;span style="color: #006080"&gt;&amp;quot;ca-ES&amp;quot;&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (cookies.AllKeys.Contains(&lt;span style="color: #006080"&gt;&amp;quot;userculture&amp;quot;&lt;/span&gt;))&lt;br /&gt;        {&lt;br /&gt;            retValue = cookies[&lt;span style="color: #006080"&gt;&amp;quot;userculture&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; retValue;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El código es trivial: derivo de ActionFilterAttribute (clase que ya existía) y redefino el método &lt;em&gt;OnActionExecuting&lt;/em&gt; que se ejecuta &lt;em&gt;antes&lt;/em&gt; de ejecutar la acción del controlador. En este método tengo el código para leer la cookie de cultura (exactamente lo mismo que tenía antes en el Route Handler).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Activar el filtro global&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Os dije que era una sóla línea en global.asax, verdad? Pues concretamente esta:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;GlobalFilters.Filters.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CookieCultureFilterAttribute());&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Otra opción es colocar esa línea dentro de la función &lt;em&gt;RegisterGlobalFilters&lt;/em&gt; que crea el VS2010, aunque entonces no es necesario usar la clase GlobalFilters (usad en su lugar el parámetro &lt;em&gt;filters&lt;/em&gt;):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;filters.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CookieCultureFilterAttribute());&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y ya está&lt;/strong&gt;. Nada más. Antes de cada acción de cualquier controlador se ejecutará el código de nuestro filtro global. &lt;strong&gt;No es necesario&lt;/strong&gt; modificar la tabla de rutas para añadir nuestro route handler.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;¿Puedo usar el filtro en una aplicación MVC2?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si, si que puedes, pero entonces debes:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Aplicarlo en cada controlador (usando [CookieCultureFilter] &lt;em&gt;antes&lt;/em&gt; de cada acción o cada controlador que quieras que use la cookie). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Derivar todos tus controladores de un controlador base que tenga [CookieCultureFilter] aplicado. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y lo más importante… ¿Ambas soluciones son equivalentes?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pues NO. Ambas soluciones no son equivalentes… En el caso del post anterior, si recordáis, si declaraba un parámetro &lt;em&gt;culture&lt;/em&gt; en una acción, recibía el valor de la cookie, ya que el route handler me añadía este parámetro en el RouteData. Pues bien, &lt;strong&gt;eso&lt;/strong&gt; dejará de funcionar. Es decir, en este caso la acción:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Foo(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; culture)&lt;br /&gt;{&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;que en el post anterior recibía el valor de la cookie en &lt;em&gt;culture&lt;/em&gt;, con esa nueva aproximación siempre recibirá &lt;em&gt;null&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¿Y por que si mi filtro también añade en el RouteData el valor de la cookie? Pues muy sencillo: el Model Binder (que se encarga de hacer binding a los parámetros de las acciones) se ejecuta &lt;strong&gt;antes&lt;/strong&gt; que el filtro. Simplificando, el flujo de ejecuciones sería:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Route Handler &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Model Binder &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Action Filters &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Acción del controlador &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este caso, estamos añadiendo un valor en el RouteData &lt;em&gt;después&lt;/em&gt; de que el Model Binder haya actuado. Por eso el parámetro no tendrá el valor. Eso no quita que desde el controlador lo podáis consultar (tenéis acceso al RouteData).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y con esto termino… espero que el post os haya ayudado un poco más a entender como funciona MVC y ver distintas alternativas de cómo hacer las cosas!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Eso es &lt;em&gt;otroooooooooooooooooo&lt;/em&gt; crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog de geeks.ms&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-833941082571888138?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/833941082571888138/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=833941082571888138' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/833941082571888138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/833941082571888138'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc-como-recuperar-un-dato-de_19.html' title='ASP.NET MVC: Como recuperar un dato de una cookie para cada petición… Una alternativa ¿igual?'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8782744209970970039</id><published>2011-01-14T13:42:00.001+01:00</published><updated>2011-01-14T13:42:35.010+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC: Como recuperar un dato de una cookie para cada petición…</title><content type='html'>&lt;p&gt;EEhhhmm… bueno, no se me ocurre un título mejor. Este post nace gracias a un tweet de &lt;a href="http://twitter.com/lluisfranco" target="_blank"&gt;Lluis Franco&lt;/a&gt;. En el tweet Lluís preguntaba &lt;a href="http://twitter.com/lluisfranco/status/25846781329801216" target="_blank"&gt;dónde guardar la cultura de una aplicación MVC&lt;/a&gt; si no se podía poner en la URL. Después de varios tweets comentando algunas cosillas yo he respondido diciendo que veía &lt;a href="http://twitter.com/eiximenis/status/25849807952154624" target="_blank"&gt;dos opciones: o en una cookie o en la base de datos&lt;/a&gt;. Una de las cosas que más me gustan de HTTP es que es simple: no hay muchas maneras de pasar estado entre cliente y servidor ;-)&lt;/p&gt;  &lt;p&gt;En este post vamos a ver como podemos solucionar fácilmente el problema asumiendo que se guarda la cultura del usuario en una cookie.&lt;/p&gt;  &lt;p&gt;De mi tweet, la parte importante es la segunda: independizar a los controladores de donde esta la cultura de la aplicación. Ya lo he comentado en varios posts: evitad acceder desde los controladores a objetos que dependen de HTTP: sesión, aplicación, cache y… cookies.&lt;/p&gt;  &lt;p&gt;En un post anterior ya comenté &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/07/09/asp-net-mvc-q-amp-a-191-c-243-mo-se-usan-las-cookies.aspx" target="_blank"&gt;como usar un value provider para hacer binding de datos de una cookie a un controlador&lt;/a&gt;. Esa es una buena solución si los datos de la cookie se usan en algunas pocas acciones de un controlador. Pero ese no es nuestro caso ahora: ahora queremos que la cultura se establezca siempre, para &lt;strong&gt;todas&lt;/strong&gt; las acciones de &lt;strong&gt;todos&lt;/strong&gt; los controladores.&lt;/p&gt;  &lt;p&gt;La solución en este caso pasa por un &lt;em&gt;Route Handler&lt;/em&gt; nuevo. Los route handlers son los objetos que se encargan de procesar las rutas (crear los controladores y cederles el control). Son pues objetos &lt;em&gt;de bajo nivel&lt;/em&gt;. Cuando la tabla de rutas enruta una URL para ser procesada por una ruta concreta, se usa el RouteHandler asociado a dicha ruta para crear toda la infrastructura que MVC necesita para procesar la petición.&lt;/p&gt;  &lt;p&gt;Recordad que la tabla de rutas se define en Global.asax y que por defecto tiene el siguiente código:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RegisterRoutes(RouteCollection routes)&lt;br /&gt;{&lt;br /&gt;    routes.IgnoreRoute(&lt;span style="color: #006080"&gt;&amp;quot;{resource}.axd/{*pathInfo}&amp;quot;&lt;/span&gt;);&lt;br /&gt;    routes.MapRoute(&lt;br /&gt;        &lt;span style="color: #006080"&gt;&amp;quot;Default&amp;quot;&lt;/span&gt;, &lt;span style="color: #008000"&gt;// Route name&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #006080"&gt;&amp;quot;{controller}/{action}/{id}&amp;quot;&lt;/span&gt;, &lt;span style="color: #008000"&gt;// URL with parameters&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; { controller = &lt;span style="color: #006080"&gt;&amp;quot;Home&amp;quot;&lt;/span&gt;, action = &lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;, id = UrlParameter.Optional } &lt;span style="color: #008000"&gt;// Parameter defaults&lt;/span&gt;&lt;br /&gt;    );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Aquí no estamos especificando ningún route handler, por lo que se usará el que tiene MVC por defecto… Pero como (casi) todo en MVC lo podemos cambiar :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En lugar de usar el método MapRoute (que por si alguien no lo sabe es un método de extensión) podemos crear un objeto Route y añadirlo directamente a la tabla de rutas. El constructor de Route tiene un parámetro que es de tipo &lt;a href="http://msdn.microsoft.com/es-es/library/system.web.routing.iroutehandler.aspx" target="_blank"&gt;IRouteHandler&lt;/a&gt; y que es el route handler para esta ruta. Así que puedo transformar la tabla de rutas anterior en esta:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RegisterRoutes(RouteCollection routes)&lt;br /&gt;{&lt;br /&gt;    routes.IgnoreRoute(&lt;span style="color: #006080"&gt;&amp;quot;{resource}.axd/{*pathInfo}&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    routes.Add(&lt;span style="color: #006080"&gt;&amp;quot;Default&amp;quot;&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Route(&lt;span style="color: #006080"&gt;&amp;quot;{controller}/{action}/{id}&amp;quot;&lt;/span&gt;, &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CultureRouteHandler())&lt;br /&gt;                {&lt;br /&gt;                    Defaults = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RouteValueDictionary(&lt;br /&gt;                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;br /&gt;                            {&lt;br /&gt;                                controller = &lt;span style="color: #006080"&gt;&amp;quot;Home&amp;quot;&lt;/span&gt;, action = &lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;, id = UrlParameter.Optional&lt;br /&gt;                            })&lt;br /&gt;                });&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ambas son equivalentes, salvo que esta usará un objeto de tipo &lt;em&gt;CultureRouteHandler&lt;/em&gt; para procesar las peticiones.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora vamos a ver como es el CultureRouteHandler:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CultureRouteHandler : MvcRouteHandler&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)&lt;br /&gt;    {&lt;br /&gt;        var cultureCookieVal = GetCultureFromCookie(requestContext.HttpContext.Request.Cookies);&lt;br /&gt;        var culture = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CultureInfo(cultureCookieVal);&lt;br /&gt;        requestContext.RouteData.Values.Add(&lt;span style="color: #006080"&gt;&amp;quot;culture&amp;quot;&lt;/span&gt;, cultureCookieVal);&lt;br /&gt;        Thread.CurrentThread.CurrentCulture = culture;&lt;br /&gt;        Thread.CurrentThread.CurrentUICulture = culture;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.GetHttpHandler(requestContext);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; GetCultureFromCookie(HttpCookieCollection cookies)&lt;br /&gt;    {&lt;br /&gt;        var retValue = &lt;span style="color: #006080"&gt;&amp;quot;ca-ES&amp;quot;&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (cookies.AllKeys.Contains(&lt;span style="color: #006080"&gt;&amp;quot;userculture&amp;quot;&lt;/span&gt;))&lt;br /&gt;        {&lt;br /&gt;            retValue = cookies[&lt;span style="color: #006080"&gt;&amp;quot;userculture&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; retValue;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este caso derivo de MvcRouteHandler (como casi siempre en MVC es mucho más sencillo derivar de alguna clase base que implementar la interfaz entera), y en el método &lt;em&gt;GetHttpHandler&lt;/em&gt; lo que hago es llamar al método de la clase base pero &lt;strong&gt;antes&lt;/strong&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Recupero el valor de la cookie de cultura &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Guardo este valor en el route data con el nombre culture (por si alguien quiere consultarlo) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Creo un CultureInfo a partir de los datos de la cookie y establezco la cultura del thread actual a este valor: así cualquier mecanismo que tenga de “localización” debería funcionar igualmente. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finalmente para probar el tema me he creado un pequeño controlador:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; HomeController : Controller&lt;br /&gt;{&lt;br /&gt;    [OutputCache(NoStore = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;, Location = OutputCacheLocation.None)]&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Index()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult SetCookie(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; id)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(id))&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ControllerContext.HttpContext.Response.Cookies.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpCookie(&lt;span style="color: #006080"&gt;&amp;quot;userculture&amp;quot;&lt;/span&gt;, id));&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; RedirectToAction(&lt;span style="color: #006080"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La acción /Home/Index simplemente retorna una vista. La acción /Home/SetCookie/id establece la cookie de cultura (se supone que el id es válido, algo así como /Home/SetCookie/es-ES p.ej.).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La vista que devuelve /Home/Index simplemente muestra la cultura actual:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    Cultura actual: @System.Threading.Thread.CurrentThread.CurrentUICulture.ToString();&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Bonus track:&lt;/strong&gt; Y si quiero que algún controlador &lt;em&gt;reciba&lt;/em&gt; la cultura actual como parámetro de alguna de sus acciones?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien, recordad que hemos hecho que el route handler guardase el valor de cultura en los route values. MVC tiene un value provider que permite realizar bindings desde los route values hacia los controladores. Guardábamos el valor con el nombre “culture” así que nos basta con:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Foo(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; culture)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Código...&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El parámetro &lt;em&gt;culture&lt;/em&gt; tiene el valor de la cultura.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si quieres saber exactamente &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/07/02/asp-net-mvc-q-amp-a-191-como-reciben-par-225-metros-los-controladores.aspx" target="_blank"&gt;cómo reciben los datos los controladores, hace algún tiempecillo escribí un post al respecto&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De esa manera conseguimos lo que yo decía en mi tweet: agnostizar los controladores de &lt;em&gt;dónde&lt;/em&gt; se guarda la cultura!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Esto es (como siempre, vamos) un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8782744209970970039?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8782744209970970039/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8782744209970970039' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8782744209970970039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8782744209970970039'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc-como-recuperar-un-dato-de.html' title='ASP.NET MVC: Como recuperar un dato de una cookie para cada petición…'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8229632884310042396</id><published>2011-01-14T10:26:00.001+01:00</published><updated>2011-01-14T10:26:06.479+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC3: Validación remota</title><content type='html'>&lt;p&gt;Muy buenas!&lt;/p&gt;  &lt;p&gt;Una de las novedades que nos trae ASP.NET MVC3, con respecto a MVC2 es poder usar &lt;em&gt;fácilmente&lt;/em&gt; la validación remota: eso es, desde &lt;em&gt;cliente&lt;/em&gt; llamar a un método del servidor que nos diga si un dato (entrado p.ej. en un campo de texto es válido o no). Y cuando digo &lt;em&gt;fácilmente&lt;/em&gt; me refiero a &lt;em&gt;fácilmente, muy fácilmente&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Vamos a ver un ejemplo: para ello vamos a modificar la aplicación de ejemplo que crea MVC3 para que al darnos de alta, consulte si el usuario ya existe y si es el caso no nos deje. Os recuerdo que esa validación es Ajax, eso significa: el campo de texto pierda el foco se realizará la petición (en background) al servidor que comprobará si el usuario entrado ya existe y si es así mostrará un error en el campo de texto asociado.&lt;/p&gt;  &lt;p&gt;Vamos pues, a verlo paso a paso ;-)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. Viendo que nos genera MVC3&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Para empezar creamos un nuevo proyecto ASP.NET MVC3. Cuando os pida el template, usad el de &lt;em&gt;Internet Application&lt;/em&gt; (no uséis el &lt;em&gt;Empty)&lt;/em&gt;. De esa manera MVC3 nos crea el esqueleto de la aplicación inicial:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_1JRa_Jfnm20/TTAWl2ocFfI/AAAAAAAAEHc/B5JeWoHbE4w/s1600-h/image2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_1JRa_Jfnm20/TTAWmqCd_kI/AAAAAAAAEHg/gvSfWiS1Fc8/image_thumb.png?imgmax=800" width="215" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;El fichero AccountModels.cs tiene distintos &lt;em&gt;Viewmodel&lt;/em&gt;s que usan las acciones del controlador Account. La acción que da de alta un usuario es Register que está definida en el controlador Account:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[HttpPost]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Register(RegisterModel model)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Código...&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La acción usa la clase RegisterModel que es uno de los &lt;em&gt;viewmodel&lt;/em&gt;s definidos en AccountModels.cs:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RegisterModel&lt;br /&gt;{&lt;br /&gt;    [Required]&lt;br /&gt;    [Display(Name = &lt;span style="color: #006080"&gt;&amp;quot;User name&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; UserName { get; set; }&lt;br /&gt;&lt;br /&gt;    [Required]&lt;br /&gt;    [DataType(DataType.EmailAddress)]&lt;br /&gt;    [Display(Name = &lt;span style="color: #006080"&gt;&amp;quot;Email address&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Email { get; set; }&lt;br /&gt;&lt;br /&gt;    [Required]&lt;br /&gt;    [ValidatePasswordLength]&lt;br /&gt;    [DataType(DataType.Password)]&lt;br /&gt;    [Display(Name = &lt;span style="color: #006080"&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Password { get; set; }&lt;br /&gt;&lt;br /&gt;    [DataType(DataType.Password)]&lt;br /&gt;    [Display(Name = &lt;span style="color: #006080"&gt;&amp;quot;Confirm password&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    [Compare(&lt;span style="color: #006080"&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;, ErrorMessage = &lt;span style="color: #006080"&gt;&amp;quot;The password and confirmation password do not match.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfirmPassword { get; set; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;2. Habilitando la validación remota&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La validación remota en MVC3 se habilita, como el resto de validaciones, usando DataAnnotations, concretamente con el atributo &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.remoteattribute(v=VS.98).aspx" target="_blank"&gt;Remote&lt;/a&gt;. En nuestro caso queremos habilitar la validación remota sobre la propiedad UserName. Para ello añado el atributo Remote:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[Required]&lt;br /&gt;[Display(Name = &lt;span style="color: #006080"&gt;&amp;quot;User name&amp;quot;&lt;/span&gt;)]&lt;br /&gt;[Remote(&lt;span style="color: #006080"&gt;&amp;quot;CheckUserAvailability&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;Account&amp;quot;&lt;/span&gt;, ErrorMessage = &lt;span style="color: #006080"&gt;&amp;quot;This user name is not allowed.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; UserName { get; set; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El primer parámetro es la acción que va a validar el campo, la segunda es el controlador. Finalmente ponemos el mensaje de error (igual que las otras validaciones).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;3. Creando el código de validación&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finalmente tenemos que crear la acción del controlador:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[OutputCache(Location = OutputCacheLocation.None, NoStore = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult CheckUserAvailability(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; username)&lt;br /&gt;{&lt;br /&gt;    var validUserName = Membership.FindUsersByName(username).Count == 0;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Json(validUserName, JsonRequestBehavior.AllowGet);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos lo simple que es: Usamos el membership provider para ver si existe algún otro usuario con el mismo nombre, y devolvemos un booleano (codificado en json). El uso de [&lt;a href="http://msdn.microsoft.com/es-es/library/system.web.mvc.outputcacheattribute.aspx" target="_blank"&gt;OutputCache&lt;/a&gt;] es para evitar que MVC me cachee los resultados de las peticiones.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Con eso ya hemos terminado.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Podemos ejecutar la aplicación, registrar un usuario y luego intentar darnos de alta de nuevo y veremos el error:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_1JRa_Jfnm20/TTAWnDHEhXI/AAAAAAAAEHk/rilKKLWELl8/s1600-h/image5.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_1JRa_Jfnm20/TTAWnocucnI/AAAAAAAAEHo/VbrEb4xQxm8/image_thumb1.png?imgmax=800" width="244" height="110" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;4. Y que pasa “en la trastienda”?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si inspeccionamos las peticiones veremos que &lt;em&gt;cada vez que cambia el texto&lt;/em&gt; se realiza una petición Ajax. Esta vez en lugar de &lt;a href="http://getfirebug.com/" target="_blank"&gt;firebug&lt;/a&gt; he usado las &lt;em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd565628(v=vs.85).aspx" target="_blank"&gt;Developer Tools&lt;/a&gt;&lt;/em&gt; de IE9 (pulsar F12 para que os aparezcan):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_1JRa_Jfnm20/TTAWoDQS4yI/AAAAAAAAEHs/_xW3-ePWqzA/s1600-h/image8.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_1JRa_Jfnm20/TTAWohvJkNI/AAAAAAAAEHw/rtitL9H4E18/image_thumb2.png?imgmax=800" width="244" height="43" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Estas son las peticiones que se realizan si entro “eiximenis” en el campo de nombre de usuario. Si las contáis &lt;em&gt;veréis que faltan peticiones&lt;/em&gt;. Eso es simplemente he pulsado dos teclas&amp;#160; muy rápido y las peticiones supongo que no se encolan&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si miramos los detalles de una petición vemos lo siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_1JRa_Jfnm20/TTAWpcUgd0I/AAAAAAAAEH0/U7sw-gZ58VA/s1600-h/image11.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_1JRa_Jfnm20/TTAWp1KTlPI/AAAAAAAAEH4/QJrOv9q4uPg/image_thumb3.png?imgmax=800" width="244" height="86" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en el primer campo (Request) me indica la URL de la petición. En mi caso es /Account/CheckUserAvailability?UserName=eiximenis&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es decir se pasa el valor por querystring (eso no es problema alguno para MVC que soporta el binding de datos en el querystring desde siempre).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;5. Y qué código me genera eso en el navegador?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Recordáis que MVC3 apuesta fuertamente por el &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/11/12/saca-tus-scripts-de-tu-c-243-digo-html.aspx" target="_blank"&gt;unobstrusive javascript&lt;/a&gt;? Pues eso es lo que nos genera:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-val&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #ff0000"&gt;data-val-remote&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;This user name is not allowed.&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #ff0000"&gt;data-val-remote-additionalfields&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;*.UserName&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #ff0000"&gt;data-val-remote-url&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;/Account/CheckUserAvailability&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #ff0000"&gt;data-val-required&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;The User name field is required.&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;UserName&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;UserName&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Precioso no? Nada de código javascript mezclado por ahí que “ensucie” el html: sólo atributos.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Los atributos data-val-remote-* son los que controlan la validación remota. Para que eso funcione, es necesario que los scripts siguientes estén referenciados:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;jquery-1.4.4.min.js &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;jquery.validate.min.js &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;jquery.validate.unobtrusive.min.js &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Yo los tengo siempre colocados en mi página Master principal (Views/Shared/_Layout.cshtml si usas Razor).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;6. Controlando algunos aspectos “avanzados”&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vamos a ver como controlar algunos aspectos más de la validación remota. P.ej. te puede interesar que la llamada a la acción de validación (CheckUserAvailability) se realice via POST y no via GET. Para ello simplemente usa la propiedad HttpMethod del atributo Remote:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[Remote(&lt;span style="color: #006080"&gt;&amp;quot;CheckUserAvailability&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;Account&amp;quot;&lt;/span&gt;,&lt;br /&gt;    HttpMethod = &lt;span style="color: #006080"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;, ErrorMessage = &lt;span style="color: #006080"&gt;&amp;quot;This user name is not allowed.&amp;quot;&lt;/span&gt;)]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Eso añade el atributo &lt;strong&gt;data-val-remote-type=&amp;quot;POST&amp;quot;&lt;/strong&gt; al campo HTML generado lo que fuerza que la petición sea usando POST. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Otra cosa interesante es que podemos &lt;strong&gt;enviar más de un parámetro &lt;/strong&gt;a la acción quen realiza la “validación remota”. P.ej. imaginad que a CheckUserAvailability le queremos también pasar el password que ha introducido el usuario (vale, no tiene lógica en ese ejemplo, pero imaginadlo igual :p).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para ello podemos usar la propiedad &lt;em&gt;AdditionalFields&lt;/em&gt; del atributo Remote:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[Remote(&lt;span style="color: #006080"&gt;&amp;quot;CheckUserAvailability&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;Account&amp;quot;&lt;/span&gt;, HttpMethod = &lt;span style="color: #006080"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;,&lt;br /&gt;    AdditionalFields = &lt;span style="color: #006080"&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;,&lt;br /&gt;   ErrorMessage = &lt;span style="color: #006080"&gt;&amp;quot;This user name is not allowed.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; UserName { get; set; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora si miramos de nuevo lo que nos manda la petición veremos que junto al campo UserName nos manda el valor del campo Password:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_1JRa_Jfnm20/TTAWqZRwvrI/AAAAAAAAEH8/FVDbLFXA8eQ/s1600-h/image%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_1JRa_Jfnm20/TTAWrY66axI/AAAAAAAAEIA/0GDFbWn5hzU/image_thumb%5B1%5D.png?imgmax=800" width="244" height="67" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tened presente que el valor de Password puede ser vacío (el usuario puede no haber introducido nada allí todavía). Pero lo importante de esto es que las validaciones remotas &lt;strong&gt;no están limitadas a validar UN SOLO campo&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y con eso terminamos el post de las validaciones remotas en ASP.NET MVC3… Como podeis ver, es un método sumamente potente y sumamente fácil!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo! ;)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Para variar eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8229632884310042396?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8229632884310042396/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8229632884310042396' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8229632884310042396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8229632884310042396'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc3-validacion-remota.html' title='ASP.NET MVC3: Validación remota'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_1JRa_Jfnm20/TTAWmqCd_kI/AAAAAAAAEHg/gvSfWiS1Fc8/s72-c/image_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-5313530974218898368</id><published>2011-01-03T11:11:00.001+01:00</published><updated>2011-01-03T11:11:39.383+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC: Binding de datos de sesión a controladores</title><content type='html'>&lt;p&gt;Muy buenas! Que tal el fin de año? Empachados con turrones, polvorones y demás? En fin, vamos a inaugurar el 2011 y que mejor manera que hacerlo que con un post! ;-)&lt;/p&gt;  &lt;p&gt;En realidad hubiese querido que este post fuese el último del año anterior, pero no puede publicarlo antes por problemas logísticos. La idea del post surge &lt;a href="http://twitter.com/luisruizpavon/status/20062211649052672" target="_blank"&gt;de un tweet que publicó Luis Ruiz Pavón.&lt;/a&gt; Su pregunta era que tal acceder a la sesión desde un Model Binder para poner datos a disposición de los controladores. &lt;a href="http://twitter.com/eiximenis/status/20062646694846464" target="_blank"&gt;Mi respuesta fue que yo usaría un value provider&lt;/a&gt;, y así llegamos a este post.&lt;/p&gt;  &lt;p&gt;Para conseguir binding de los datos de la sesión a los parámetros de un controlador no es necesario crear ningún Model Binder. En MVC2 se introdujo un concepto nuevo (del que ya he hablado varias veces por aquí) que se llama ValueProvider y que es el encargado de &lt;em&gt;acceder donde están los datos y ponerlos a disposición de los Model Binders&lt;/em&gt;. Si ignoramos los value providers y hacemos un model binder que acceda a la sesión, entonces realmente nuestro model binder hace dos cosas:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Ir donde están los datos (la sesión) y recogerlos &lt;/li&gt;    &lt;li&gt;Enlazar los datos con los parámetros de los controladores &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Según la arquitectura de ASP.NET MVC los model binders sólo se encargan de lo segundo, y son los value providers quienes se encargan de lo primero. Así, pues, tened presente la regla:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Si lo que queréis canviar es &lt;strong&gt;cómo&lt;/strong&gt; se enlazan los datos (vengan de donde vengan) a los controladores: cread un model binder &lt;/li&gt;    &lt;li&gt;Si lo que queréis es &lt;strong&gt;modificar de dónde &lt;/strong&gt;se obtienen los datos que se enlazan a los controladores: usad un value provider. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;En nuestro caso, tal y como se enlazan los valores a los controladores ya nos va bien (el DefaultModelBinder es realmente bueno en su tarea), sólo que queremos que si un dato está en la sesión se coja de allí: necesitamos un value provider nuevo.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Factoría de value providers&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;En ASP.NET MVC los value providers se crean siempre mediante una factoría y lo que realmente registramos en el runtime son esas factorías. En cada petición ASP.NET MVC le pide a las distintas factorías que creen los value providers necesarios.&lt;/p&gt;  &lt;p&gt;Así pues lo primero va a ser crear nuestra factoría, que devolverá objetos de &lt;em&gt;nuestro&lt;/em&gt; value provider vinculado a sesión:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SessionValueProviderFactory : ValueProviderFactory&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IValueProvider GetValueProvider(ControllerContext controllerContext)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SessionValueProvider(controllerContext.HttpContext.Session);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simplemente debemos derivar de ValueProviderFactory y en el método GetValueProvider devolver una instancia de nuestro value provider. En mi caso devuelvo una instancia del SessionValueProvider y le paso la sesión en el constructor.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Debemos registrar esa factoría de value providers en el runtime de ASP.NET MVC. Para ello en el Global.asax basta con meter la siguiente línea (usualmente en el Application_Start):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;ValueProviderFactories.Factories.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SessionValueProviderFactory());&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;El value provider&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Crear un value provider es “tan sencillo” como implementar la interfaz IValueProvider. De todos modos debemos conocer un poco como funcionan los model binders a los que debemos proporcionar los valores.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Los value providers vienen a ser como un “diccionario enorme” que los model binders consultan cuando quieren obtener un dato. Debemos saber cómo (“con que clave”) nos va a pedir el model binder los datos y como debemos dárselos. En un post mío de hace tiempo &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/05/10/asp-net-mvc-el-defaultmodelbinder.aspx" target="_blank"&gt;ya comenté como funciona el DefaultModelBinder&lt;/a&gt;, y allí cuento también la interacción entre el DefaultModelBiner y los value providers. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En fin, que todo ese rollete es para comentaros que muchas veces en lugar de implementar IValueProvider desde cero, es mucho mejor derivar de alguna de las clases que ya hay hechas, y hay una en concreto que nos viene al pelo&lt;a href="http://msdn.microsoft.com/es-es/library/ee703471.aspx" target="_blank"&gt;: DictionaryValueProvider&amp;lt;TValue&amp;gt;&lt;/a&gt;. Esta clase implementa un value provider cuya fuente de datos es un diccionario cuyos valores son de tipo TValue. Y que es la sesión en el fondo sinó un gran diccionario cuyos valores son de tipo object?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues creamos nuestra clase que derive de DictionaryValueProvider y lo único que tenemos que hacer es pasarle a nuestra clase base el diccionario que debe usar, que construimos a partir de la sesión:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SessionValueProvider : DictionaryValueProvider&amp;lt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; SessionValueProvider(HttpSessionStateBase session)&lt;br /&gt;        : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(CreateDictionary(session), CultureInfo.CurrentCulture)&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; CreateDictionary(HttpSessionStateBase session)&lt;br /&gt;    {&lt;br /&gt;        var entries = session.Keys.Cast&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;().ToDictionary(key =&amp;gt; key, key =&amp;gt; session[key]);&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; entries;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Trivial no? El método CreateDictionary simplemente crea un IDictionary a partir de los datos de la sesión.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y listos!&lt;/strong&gt; Hemos terminado, No necesitamos hacer nada más para que el binding de objetos de sesión funcione. El requisito para que el binding se efectúe es el de siempre: que el nombre del parámetro en la acción del controlador tenga el mismo nombre que la clave de sesión:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SessionController : Controller&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Put()&lt;br /&gt;    {&lt;br /&gt;        Session[&lt;span style="color: #006080"&gt;&amp;quot;ufo&amp;quot;&lt;/span&gt;] = &lt;span style="color: #006080"&gt;&amp;quot;String en sessión&amp;quot;&lt;/span&gt;;&lt;br /&gt;        Session[&lt;span style="color: #006080"&gt;&amp;quot;complex&amp;quot;&lt;/span&gt;] = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Foo()&lt;br /&gt;                                 {&lt;br /&gt;                                     Cadena = &lt;span style="color: #006080"&gt;&amp;quot;Una cadena en objeto complejo&amp;quot;&lt;/span&gt;,&lt;br /&gt;                                     Entero = 100,&lt;br /&gt;                                     Lista = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt;() {1, 1, 3, 5, 8, 13}&lt;br /&gt;                                 };&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult Get(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ufo)&lt;br /&gt;    {&lt;br /&gt;        ViewData[&lt;span style="color: #006080"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;] = ufo;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult GetClass(Foo complex)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; View(complex);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En este controlador la acción Put coloca dos datos en la sesión: una cadena con clave “ufo” y un objeto de una clase llamada Foo, con clave “complex”. Las dos acciones restantes (Get y GetClass) usan el binding y obtienen los datos de la sesión.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Ventajas de usar el binding para obtener los valores&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La ventaja principal de usar el binding para obtener los valores en lugar de acceder a la sesión directamente es que desacopla el código de las acciones de la sesión de HTTP. En definitiva, si quiero probar si la acción Get funciona correctamente, p.ej. usando un unit test, me basta con pasarle una cadena cualquiera. Si en el código de la acción accediese a la sesión debería tener acceso a la sesión (desde la prueba) y rellenarla.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Espero que os sea útil!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Teneis un proyecto en VS2010 con MVC2 con el código de dicho post en mi skydrive: &lt;a title="http://cid-6521c259e9b1bec6.office.live.com/self.aspx/BurbujasNet/ZipsPosts/MvcSessionBinding.zip" href="http://cid-6521c259e9b1bec6.office.live.com/self.aspx/BurbujasNet/ZipsPosts/MvcSessionBinding.zip"&gt;http://cid-6521c259e9b1bec6.office.live.com/self.aspx/BurbujasNet/ZipsPosts/MvcSessionBinding.zip&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Como siempre: esto es un crosspost desde &lt;a href="http://geeks.ms/members/etomas/default.aspx" target="_blank"&gt;mi blog bn geeks.ms&lt;/a&gt;. Pásate por allí mejor!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-5313530974218898368?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/5313530974218898368/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=5313530974218898368' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5313530974218898368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/5313530974218898368'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2011/01/aspnet-mvc-binding-de-datos-de-sesion.html' title='ASP.NET MVC: Binding de datos de sesión a controladores'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-1685544565638718107</id><published>2010-12-21T15:01:00.001+01:00</published><updated>2010-12-21T15:01:00.123+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Opinión: Var o no var… esa es la cuestión.</title><content type='html'>&lt;p&gt;Hola a todos! Desde hace algunos días estoy usando &lt;a href="http://www.jetbrains.com/resharper/" target="_blank"&gt;Resharper&lt;/a&gt;. La verdad no era, como decirlo, muy proclive para instalármelo, ya que había tenido no muy buenas experiencas con &lt;a href="http://www.devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/" target="_blank"&gt;&lt;em&gt;CodeRush&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. &lt;/em&gt;Seguramente no eran culpa de CodeRush sinó mías, pero bueno… Al final me lo instalé y debo decir que estoy gratamente sorprendido: Es una auténtica maravilla.&lt;/p&gt;  &lt;p&gt;Una cosa interesante de Resharper es que te hace &lt;em&gt;sugerencias&lt;/em&gt; (que puedes desactivar si quieres, por supuesto) sobre como &lt;em&gt;codificar mejor&lt;/em&gt;. Y una de las sugerencias es usar var &lt;strong&gt;siempre que se pueda&lt;/strong&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_1JRa_Jfnm20/TRCzF8ouojI/AAAAAAAAEGc/3jRIzPvlPys/s1600-h/image2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_1JRa_Jfnm20/TRCzG2WnfVI/AAAAAAAAEGg/Qjdv4hdxT-c/image_thumb.png?imgmax=800" width="244" height="60" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Fijaos que incluso en un caso &lt;strong&gt;trivial&lt;/strong&gt; como int i=0; nos recomienda que usemos var.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;Nota: Primero una pequeña aclaración sobre var: &lt;/strong&gt;Por si acaso… Recordad que var &lt;strong&gt;no es tipado dinámico&lt;/strong&gt;, ni late-binding ni nada parecido a esto. Var simplemente le indica al &lt;em&gt;compilador&lt;/em&gt; que infiera él el tipo de la variable. Pero la variable &lt;em&gt;tiene&lt;/em&gt; un tipo concreto &lt;em&gt;y lo tiene en tiempo de compilación&lt;/em&gt;. Por lo tanto olvidad todos vuestros prejuicios (si los tenéis) sobre tipos dinámicos.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Hay tres corrientes de opinión al respecto de cuando usar var: Hay gente que opina que debe usarse &lt;em&gt;sólo&lt;/em&gt; cuando es necesario (cuando se trabaja con objetos anónimos). &lt;/p&gt;  &lt;p&gt;Otros opinan que cuando el tipo ya aparece en la lína de código puede usarse var. Es decir, admiten esto:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var dict = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Porque el tipo de la variable ya aparece en el new. Pero no admiten lo siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var result = stockManager.GetStocks();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Porque, viendo el código: como se puede saber el tipo de &lt;em&gt;result&lt;/em&gt;? (Debes irte a ver que devuelve el método GetStocks).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por último el tercer grupo de opinión está a favor de usar var siempre. Incluso en los casos más triviales.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por curiosidad:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;La msdn se situa en el primer grupo de opinión (literalmente dice “&lt;em&gt;the use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required” - &lt;a title="http://msdn.microsoft.com/en-us/library/bb384061.aspx" href="http://msdn.microsoft.com/en-us/library/bb384061.aspx"&gt;http://msdn.microsoft.com/en-us/library/bb384061.aspx&lt;/a&gt;&lt;/em&gt;). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Resharper se sitúa en el tercer grupo, como hemos visto &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Yo me situaba en el segundo grupo de opinión. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;¿Que aporta usar siempre var?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Que Resharper me estuviese continuamente insistiendo en usar &lt;em&gt;var&lt;/em&gt; me hizo pensar en el &lt;em&gt;por que&lt;/em&gt; de esa razón. Así que lo que hice fue probar y hacerle caso. Y empecé a usar &lt;em&gt;var&lt;/em&gt; en todos los sitios. A ver que ocurría.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y ocurrió una cosa interesante…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Al usar &lt;em&gt;var&lt;/em&gt; continuamente pierdes el &lt;em&gt;tipo&lt;/em&gt; de la variable de forma visual (es decir no sabes de que tipo es sólo viendo esa línea de código) y entonces te das cuenta de una cosa: que muchos nombres de variables &lt;strong&gt;aportan muy poca información&lt;/strong&gt; sobre que hace realmente la variable. Los detractores de var dicen que puede complicar la lectura de código… pero que es más dificil de entender, esto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Player plr = GetCurrentPlayer();&lt;br /&gt;Location l = plr.GetCustomLocation();&lt;br /&gt;// Varias líneas de código hablando de &lt;span style="color: #006080"&gt;&amp;quot;l&amp;quot;&lt;/span&gt; y &lt;span style="color: #006080"&gt;&amp;quot;plr&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;o esto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var player = GetCurrentPlayer();&lt;br /&gt;var location = player.GetCustomLocation();&lt;br /&gt;&lt;span style="color: #008000"&gt;// Varias líneas de código hablando de &amp;quot;location&amp;quot; y &amp;quot;player&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El tema está en que la variable la declaras en una línea, y la usas en varias más. Evidentemente, si no usas var, la línea que declara la variable te da más información (exactamente el tipo de la variable), información que pierdes si usas var. Pero, como te das cuenta que estás &lt;em&gt;perdiendo&lt;/em&gt; esta información, lo que haces es usar lo que resta de la línea para aumentar la claridad. Y que es lo que queda? El nombre de la variable.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Al usar var en todos los sitios &lt;em&gt;te fuerzas&lt;/em&gt; a poner nombres más declarativos a tus variables, que expresen lo que la variable hace. Y todos sabemos que esa &lt;strong&gt;es una muy buena práctica&lt;/strong&gt;. Y a veces no la seguimos, y una de las razones es que al tener una línea tipo:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Location l = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Location();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mentalmente piensas: &lt;em&gt;&amp;lt;&amp;lt;Ya se ve que “l” es una Location. Ya queda claro.&amp;gt;&amp;gt;&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero no es cierto, porque al cabo de unas cuantas líneas te aparece una “l” y tienes que recordad que era una &lt;em&gt;Location&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mientras que si usas var, cuando escribes la línea tiendes a usar nombres más descriptivos, porque escribir:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var l = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Location();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Hace como daño a la vista :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así que la sugerencia de usar &lt;em&gt;var &lt;/em&gt;siempre, personalmente no me parece muy desacertada, y creo que voy a tomar esa opción de ahora en adelante.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero… Y vosotros? ¿Que opináis al respecto?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;PD:&lt;/strong&gt;&amp;#160; También creo que hay otra razón para que Resharper nos guie a usar siempre var y es que el código con var es más fácil de refactorizar (menos cambios) que el que usa declaraciones explícitas.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Como no… otro crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx" target="_blank"&gt;mi blog de geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-1685544565638718107?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/1685544565638718107/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=1685544565638718107' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1685544565638718107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/1685544565638718107'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/12/opinion-var-o-no-var-esa-es-la-cuestion.html' title='Opinión: Var o no var… esa es la cuestión.'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_1JRa_Jfnm20/TRCzG2WnfVI/AAAAAAAAEGg/Qjdv4hdxT-c/s72-c/image_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-4042207031013555027</id><published>2010-12-16T14:21:00.001+01:00</published><updated>2010-12-16T14:21:15.439+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET: Obtener el ID del usuario actual</title><content type='html'>&lt;p&gt;Buenas!&lt;/p&gt;  &lt;p&gt;No se vosotros, pero yo cuando desarrollo mis aplicaciones, si uso FKs de la otabla de usuarios, las hago en base al ID del usuario, nunca en base a su nombre. Así pues, saber el ID del usuario actualmente autenticado en mi aplicación es algo fundamental.&lt;/p&gt;  &lt;p&gt;Primero, para saber el &lt;strong&gt;nombre&lt;/strong&gt; del usuario autenticado podemos usar:&lt;/p&gt;    &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; userName = HttpContext.Current.User.Identity.Name;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El tema está en que las mentes pensantes que parieron el sistema de proveedores de autenticación en ASP.NET no tuvieron a bien a poner un campo para guardar el ID.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por suerte obtenerlo es trivial:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;)Membership.GetUser().ProviderUserKey;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;u&gt;Ojo con ese código:&lt;/u&gt;&lt;/strong&gt; Yo uso un membership provider propio, ya que mi base de datos usa ints para los IDs de usuarios. Si usáis el membership provider que viene por defecto en ASP.NET, el cast lo debéis hacer a Guid y no int.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bueno todo muy bonito, pero antes que descorchéis el cava: eso &lt;strong&gt;hace una llamada a la base de datos&lt;/strong&gt;. Además se trae &lt;em&gt;todos los campos&lt;/em&gt; del registro correspondiente de la tabla de usuarios (que si usáis el membership provider que viene por defecto tiene la hostia y pico). O sea que cuidado con usar eso a mansalva… :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Eeeerrr… ¿se puede SIN necesidad de acceder a la base de datos?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bueno… esa es la gran pregunta, no nos vamos a engañar ;-) Hay varias maneras de poder acceder al ID del usuario &lt;em&gt;sin&lt;/em&gt; hacer un round-trip a la base de datos, pero a si a bote pronto se me ocurren dos:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Guardarlo en una variable de sesión: Podemos guardar el ID en una variable de sesión y consultarla cuando la necesitamos. Para una escalabilidad máxima podéis no usar &lt;em&gt;sticky sessions&lt;/em&gt; y en el Session_Start guardar dicha variable con el ID. Si no usáis sticky sessions un mismo usuario puede iniciar sesión en varios IIS a la vez, pero en nuestro caso no es problemático (simplemente se consultará el ID del usuario cada vez que inicie sesión). Eso sí, estoy asumiendo que &lt;strong&gt;no&lt;/strong&gt; guardáis nada más en la sesión (es decir que funcionalmente &lt;em&gt;no&lt;/em&gt; dependéis de la sesión). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Guardarlo en la cookie de autenticación del usuario. Esto no es, ni de lejos tan sencillo como el punto anterior, pero ya que hemos llegado hasta aquí… &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Modificar la cookie de autenticación&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Primero debemos hacer que cuando se cree la cookie de autenticación se añada el ID del usuario. En mi caso, como siempre, uso ASP.NET MVC, así que modificaré el código de AccountController (que es el que genera VS). Para aplicaciones webforms ese código debe colocarse cuando se va a hacer login del usuario.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En el código por defecto que genera VS para autenticar un usuario se usa:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SignIn(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; userName, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; createPersistentCookie)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(userName)) &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(&lt;span style="color: #006080"&gt;&amp;quot;Value cannot be null or empty.&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;userName&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Este código está en la clase &lt;em&gt;FormsAuthenticationService&lt;/em&gt; (dentro de AccountsModel.cs) y no tiene ningún secreto: lo que hace es crear la cookie de autenticación de ASP.NET.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En nuestro caso vamos a modificar ese código por el siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SignIn(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; userName, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; createPersistentCookie)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(userName)) &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(&lt;span style="color: #006080"&gt;&amp;quot;Value cannot be null or empty.&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;userName&amp;quot;&lt;/span&gt;);&lt;br /&gt;    FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id = 100;        &lt;span style="color: #008000"&gt;// Aquí va el ID del usuario que pillaríamos de la BBDD&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; userData = &lt;font color="#0000ff"&gt;id.ToString();&lt;span style="color: #0000ff"&gt;&lt;/span&gt;&lt;/font&gt;&lt;br /&gt;    FormsAuthenticationTicket ticket = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), createPersistentCookie, userData); &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; encTicket = FormsAuthentication.Encrypt(ticket); &lt;br /&gt;    HttpCookie faCookie = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpCookie(FormsAuthentication.FormsCookieName, encTicket); &lt;br /&gt;    HttpContext.Current.Response.Cookies.Add(faCookie);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lo que hacemos es crear una cookie, con datos adicionales (el ID del usuario).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora lo que nos toca es la otra parte: reemplazar el valor de HttpContext.Current.User.Identity por uno propio que tenga el ID. Para ello usamos el evento Post&lt;em&gt;Authenticate_Request&lt;/em&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Application_PostAuthenticateRequest(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (authCookie != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);&lt;br /&gt;        CustomIdentity identity = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomIdentity(authTicket.Name, authTicket.UserData);&lt;br /&gt;        GenericPrincipal newUser = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; GenericPrincipal(identity, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] {});&lt;br /&gt;        Context.User = newUser;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Recogemos la cookie de autenticación, desencriptamos el ticket de autenticación por forms y con los datos (el nombre y el UserData) creamos un objeto de tipo CustomIdentity, clase nuestra que nos implementa IIdentity. Luego la incrustamos dentro de un GenericPrincipal y lo establecemos a la propiedad User del HttpContext.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; El segundo parámetro del constructor de GenericPrincipal es el array de roles a los que pertenece el usuario. En mi caso no uso roles, así que le asigno un array vacío.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La clase CustomIdentity es tal y como sigue:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CustomIdentity : IIdentity&lt;br /&gt;  {&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; CustomIdentity(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; id)&lt;br /&gt;      {&lt;br /&gt;          IsAuthenticated = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;br /&gt;          Name = name;&lt;br /&gt;          Id = Int32.Parse(id);&lt;br /&gt;          AuthenticationType = &lt;span style="color: #006080"&gt;&amp;quot;Forms&amp;quot;&lt;/span&gt;;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; AuthenticationType { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set; }&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsAuthenticated { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set; }&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set;}&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Id { get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set; }&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De esta manera, ahora podemos al Id del usuario, desde un controlador:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;CustomIdentity ci = (CustomIdentity)ControllerContext.HttpContext.User.Identity;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; IdUsuario = ci.Id;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un misterio con el que me he encontrado es que el código de PostAuthenticateRequest si se pone en AuthenticateRequest (que parece que debería funcionar igual), se queja diciendo que la clase “CustomIdentity” no es serializable. No tengo muy claro porque ocurre eso y eso si que parece ser propio de MVC. Aquí hay más información al respecto: &lt;a title="http://stackoverflow.com/questions/1884030/implementing-a-custom-identity-and-iprincipal-in-mvc" href="http://stackoverflow.com/questions/1884030/implementing-a-custom-identity-and-iprincipal-in-mvc"&gt;http://stackoverflow.com/questions/1884030/implementing-a-custom-identity-and-iprincipal-in-mvc&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y Listos! &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Con esto podemos acceder al ID de nuestros usuarios sin necesidad de usar para nada la base de datos. Además, dado que estamos usando el sistema de autenticación de ASP.NET (no hacemos nada &lt;em&gt;raro&lt;/em&gt;), nos siguen funcionando los filtros de autenticación como [Authorize].&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Referencia:&lt;/strong&gt; &lt;a title="http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal" href="http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal"&gt;http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Eso es (como siempre) un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/" target="_blank"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-4042207031013555027?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/4042207031013555027/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=4042207031013555027' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4042207031013555027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4042207031013555027'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/12/aspnet-obtener-el-id-del-usuario-actual.html' title='ASP.NET: Obtener el ID del usuario actual'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-6205765457620597977</id><published>2010-11-23T11:41:00.001+01:00</published><updated>2010-11-23T11:41:15.910+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>Trick: Enviar datos en JSON usando POST</title><content type='html'>&lt;p&gt;Muy buenas!&lt;/p&gt;  &lt;p&gt;Una de las preguntas que mucha gente se formula cuando empieza a hacer cosillas con ajax y jQuery es &lt;em&gt;¿Como enviar datos codificados en JSON usando POST&lt;/em&gt;? &lt;/p&gt;  &lt;p&gt;La verdad es que es muy sencillo, aunque jQuery no proporciona ninguna función &lt;em&gt;por defecto&lt;/em&gt; que haga esto. Vamos a ver tres aproximaciones, las dos primeras incorrectas pero que nos acercarán para llegar al final a &lt;strike&gt;la&lt;/strike&gt; una forma correcta de hacerlo.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Aproximación 1: Usando $.post&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;jQuery tiene una función específica para enviar datos usando post, llamada &lt;a href="http://api.jquery.com/jQuery.post/"&gt;$.post&lt;/a&gt;. Así podriamos pensar que el siguiente método funcionaria:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; JsonPost(data, url, handler)&lt;br /&gt;{&lt;br /&gt;    $.post(url, data, handler);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y luego podríamos llamarlo de la siguiente manera:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// Envia un objeto con propiedades Col y Row a /Map/ViewPort y&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// llama a fillMap con el resultado devuelto&lt;/span&gt;&lt;br /&gt;JsonPost({ Col: c, Row: r}, &lt;span style="color: #006080"&gt;&amp;quot;/Map/Viewport&amp;quot;&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(data) {&lt;br /&gt;    fillMap(data);&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero eso no realiza una petición JSON. Si usamos, p.ej. Firebug para analizar la petición vemos que lo que se envía al controlador es:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_1JRa_Jfnm20/TOuaO2UmFgI/AAAAAAAAEFg/OT2wPe5J0fw/s1600-h/image2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_1JRa_Jfnm20/TOuaPrMZ6xI/AAAAAAAAEFk/v-DT2AlCcco/image_thumb.png?imgmax=800" width="244" height="118" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si os fijáis los datos no están codificados en JSON, sinó en el formato “estándard” (param=value&amp;amp;param=value&amp;amp;…)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si se lee la documentación de $.post() se ve que acepta un último parámetro &lt;em&gt;datatype&lt;/em&gt;, así que podríamos pensar que poniendo dicho parámetro a “json” funcionará, pero no. El parámetro “datatype” indica &lt;strong&gt;el tipo de datos esperado de vuelta&lt;/strong&gt;, no el que se envia.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Resumiendo: $.post() &lt;strong&gt;siempre envía los datos en el formato &lt;em&gt;tradicional&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Aproximación 2: Usando $.post() y convertir los datos a Json&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De acuerdo, hemos visto que $.post() nos transforma nuestro objeto javascript en la cadena &lt;em&gt;tradicional&lt;/em&gt; de param=value&amp;amp;param=value&amp;amp;… Pero si a $.post() se le pasa una cadena la manda &lt;em&gt;tal cual&lt;/em&gt;, por lo que si transformamos el objeto javascript a una cadena JSON parece que todo funcionará.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para transformar un objeto javascript a notación JSON podemos usar el plugin &lt;a href="http://code.google.com/p/jquery-json/"&gt;jQuery-Json&lt;/a&gt;. Puede haber otros plugins por ahí, pero uséis el que uséis, &lt;strong&gt;aseguraros que soporta &lt;a href="http://www.west-wind.com/weblog/posts/729630.aspx"&gt;native json&lt;/a&gt;&lt;/strong&gt;. Native json es una funcionalidad que los nuevos navegadores traen y que se basa en un método llamado JSON.stringify que transforma el objeto pasado a una cadena json. Evidentemente siempre será mucho más rápido si el propio navegador puede hacer esto de forma nativa que si es código javascript que construye la cadena. El plugin jQuery-json usa JSON.stringify si está disponible y sólo en caso de que no exista usa código javascript.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues podríamos modificar nuestra JsonPost para que quede como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; JsonPost(data, url, handler)&lt;br /&gt;{&lt;br /&gt;    $.post(url,$.toJSON(data), handler);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El método $.toJSON es el método proporcionado por el plugin. Ahora sí que estamos usando JSON para enviar los datos:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_1JRa_Jfnm20/TOuaQMPXu_I/AAAAAAAAEFo/i3lb3etkEXU/s1600-h/image11.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_1JRa_Jfnm20/TOuaRgtihkI/AAAAAAAAEFs/qFkyMSntNGU/image_thumb3.png?imgmax=800" width="244" height="89" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ok. Un parentesis: Recordad que MVC2 &lt;strong&gt;no tiene soporte directo para realizar binding de datos enviados en JSON&lt;/strong&gt;. Aunque &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/06/01/asp-net-mvc-custom-model-binders-vs-valueproviders-y-un-ejemplo-con-json.aspx"&gt;es muy fácil crearse un Value Provider propio que de soporte a JSON en MVC2&lt;/a&gt;. Y recordad que MVC3 ya viene con el soporte por defecto de JSON.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien, si usáis un value provider para JSON que os hayais encontrado por “ahí afuera” lo más probable es que no os funcione, es decir que en el controlador no recibáis los datos. Por que? Pues por lo que está marcado en rojo en la imagen antrior: aunque estamos enviando los datos en formato json, el content-type no es correcto. El content-type de JSON es &lt;em&gt;application/json &lt;/em&gt;y este es el content-type que suelen mirar los value providers de JSON.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Aproximación 3: Usando $.ajax()&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien, ya que $.post() no permite especificar el content-type, la tercera y última aproximación es usar &lt;a href="http://api.jquery.com/jQuery.ajax/"&gt;$.ajax()&lt;/a&gt;, que es la función más personalizable que tiene jQuery para hacer peticiones ajax.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De hecho básicamente lo único que tenemos que cambiar respecto la aproximación anterior es el content-type:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; JsonPost(data, url, handler)&lt;br /&gt;{&lt;br /&gt;    $.ajax(&lt;br /&gt;    {&lt;br /&gt;        url: url,&lt;br /&gt;        type: &lt;span style="color: #006080"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;,&lt;br /&gt;        success: handler,&lt;br /&gt;        data: $.toJSON(data),&lt;br /&gt;        contentType: &lt;span style="color: #006080"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;br /&gt;    });&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y lo que nos muestra Firebug de la petición:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_1JRa_Jfnm20/TOuaSEpDdtI/AAAAAAAAEFw/pAJPJA033TA/s1600-h/image%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_1JRa_Jfnm20/TOuaS_BGUpI/AAAAAAAAEF0/RXfxHnCIwlY/image_thumb%5B1%5D.png?imgmax=800" width="244" height="83" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que ahora el propio Firebug reconoce que la petición es en JSON y me muestra los datos en JSON.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Espero que os sea útil! &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como no… otro crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-6205765457620597977?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/6205765457620597977/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=6205765457620597977' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6205765457620597977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6205765457620597977'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/trick-enviar-datos-en-json-usando-post.html' title='Trick: Enviar datos en JSON usando POST'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_1JRa_Jfnm20/TOuaPrMZ6xI/AAAAAAAAEFk/v-DT2AlCcco/s72-c/image_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-7132176497833476105</id><published>2010-11-19T12:24:00.001+01:00</published><updated>2010-11-19T12:24:01.053+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>[Evento] Hasta donde se puede llegar con ASP.NET MVC?</title><content type='html'>&lt;p&gt;Muy buenas!&lt;/p&gt;  &lt;p&gt;El jueves &lt;strong&gt;2 de diciembre&lt;/strong&gt; voy a realizar un WebCast para la gente del &lt;a href="http://lleida.dotnetclubs.com/"&gt;Lleida DotNetClub&lt;/a&gt; sobre ASP.NET MVC.&lt;/p&gt;  &lt;p&gt;La idea es empezar desde cero a desarrollar una aplicación ASP.NET MVC y ver hasta donde llegamos. Iremos explorando el framework y viendo paso a paso sus características: controladores, vistas, modelos, vistas parciales, ajax, helpers, inyección de dependencias,…&lt;/p&gt;  &lt;p&gt;La idea es que sea 100% Visual Studio, nada de powerpoints que de esto ya se encuentra mucho en la web!&lt;/p&gt;  &lt;p&gt;La página de registro está en &lt;a title="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032471331&amp;amp;EventCategory=4&amp;amp;culture=es-ES&amp;amp;CountryCode=ES" href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032471331&amp;amp;EventCategory=4&amp;amp;culture=es-ES&amp;amp;CountryCode=ES"&gt;https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032471331&amp;amp;EventCategory=4&amp;amp;culture=es-ES&amp;amp;CountryCode=ES&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Así que si estás interesado en ver ASP.NET MVC, ya sabes: te esperamos! ;-)&lt;/p&gt;  &lt;p&gt;Saludos y gracias a la gente del Lleida DotNetClub por invitarme a dar la charla! :)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;PD:&lt;/strong&gt; Huelga decir que si tienes cualquier comentario sobre &lt;em&gt;algo&lt;/em&gt; específico que te gustaría ver en este Webcast coméntalo por aquí y voy a ver como se puede encajar! De lo que se trata es que este Webcast sea interesante &lt;em&gt;para vosotros&lt;/em&gt;!&lt;/p&gt;  &lt;p&gt;PD2: Pues sí… Eso es oooooooootro crosspost de &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog de geeks.ms&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-7132176497833476105?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/7132176497833476105/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=7132176497833476105' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/7132176497833476105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/7132176497833476105'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/evento-hasta-donde-se-puede-llegar-con.html' title='[Evento] Hasta donde se puede llegar con ASP.NET MVC?'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-4784148144314985399</id><published>2010-11-18T14:53:00.001+01:00</published><updated>2010-11-18T14:53:17.578+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# Básico: Covarianza en genéricos</title><content type='html'>&lt;p&gt;Muy buenas! Hacía tiempo que no escribía nada de la &lt;a href="http://geeks.ms/blogs/etomas/archive/tags/c_2300_+basico/default.aspx"&gt;serie C# Básico&lt;/a&gt;. En esta serie voy tratando temas (sin ningún orden en particular) que considero que son fundamentos más o menos elementales del lenguaje. No es un tutorial al uso, cada post es independiente del resto y como digo no están ordenados por nada en particular.&lt;/p&gt;  &lt;p&gt;El post de hoy nace a raíz de una pregunta que vi en los foros de msdn (&lt;a title="http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/daf808ed-a0aa-4e1e-88ed-64ee60cce918" href="http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/daf808ed-a0aa-4e1e-88ed-64ee60cce918"&gt;http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/daf808ed-a0aa-4e1e-88ed-64ee60cce918&lt;/a&gt;), donde un usuario preguntaba porque el intentar convertir una List&amp;lt;LogVehiculos&amp;gt; a List&amp;lt;Log&amp;gt; le daba error teniendo en cuenta que LogVehiculos derivaba de Log.&lt;/p&gt;  &lt;p&gt;Mi respuesta fue que en C# 3.5 los genéricos no son covariantes, y este post es para explicarlo todo un poco más :)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Antes que nada&lt;/strong&gt;, covarianza y contravarianza son dos palabrejas muy molonas para explicar dos conceptos que son muy básicos pero que tienen implicaciones muy profundas. El &lt;strong&gt;mejor artículo en español que he leído sobre covarianza y contravarianza&lt;/strong&gt; es el del &lt;em&gt;Doctor&lt;/em&gt; (maestros hay algunos, doctores muchos menos) &lt;strong&gt;&lt;a href="http://miguelkatrib.sys-con.com/"&gt;Miguel Katrib&lt;/a&gt;&lt;/strong&gt; que salió publicado en la &lt;a href="http://www.dotnetmania.com/"&gt;DotNetMania&lt;/a&gt; número 62 y titulado “La danza de las varianzas”. Es un artículo que debe leerse con atención pero sin duda de lo mejorcito que he leído nunca. Este post no entrará ni mucho menos en la profundidad de dicho artículo, así que si os interesa el tema, ya sabeis: haceros con dicha DotNetMania. &lt;/p&gt;  &lt;p&gt;En este post nos vamos a centrar sólamente en la covarianza.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Covarianza&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Llamamos covarianza a algo muy simple: Cuando permitimos sustituir un tipo D por otro tipo B. Para que eso sea posible debe cumplirse una condición: Que no haya nada que pueda hacerse con B y NO pueda hacerse con D.&lt;/p&gt;  &lt;p&gt;Vamos a suponer que tenemos una clase Animal, de la cual deriva la clase Perro:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Animal&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Comer() { ... }&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dormir() { ... }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Perro : Animal&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; VigilarCasa() { ... }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si tenemos un método cualquiera que devuelva un perro, nosotros podemos convertir el resultado a un animal:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Perro ComprarPerro() { ... }&lt;br /&gt;&lt;span style="color: #008000"&gt;// entonces eso es válido:&lt;/span&gt;&lt;br /&gt;Animal animal = ComprarPerro();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;Eso&lt;/em&gt; es covarianza: el poder sustituir la clase derivada (Perro) que devuelve el método con la clase base (Animal). C# soporta covarianza entre una clase derivada y su clase base (como hacen de hecho &lt;em&gt;todos&lt;/em&gt; los lenguajes orientados a objetos).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tiene lógica, porque fijaos que &lt;strong&gt;no&lt;/strong&gt; hay nada que pueda hacerse con un Animal (B) que no pueda hacerse con un Perro (D): Dado que Perro deriva de Animal hereda todos sus métodos y propiedades.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero la covarianza se da también en más casos y algunos de ellos están soportados en C#. Veamos…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Covarianza en delegados&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Se trata de poder asignar a un delegado que devuelve un Animal un método que devuelve un Perro:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt; Animal AnimalDelegate();&lt;br /&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Program&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Perro ObtenerPerro() { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro(); }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Animal ObtenerAnimal() { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Animal(); }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;    {&lt;br /&gt;        Animal animal = ObtenerPerro();&lt;br /&gt;        AnimalDelegate ad = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AnimalDelegate(ObtenerAnimal);&lt;br /&gt;        AnimalDelegate ad2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AnimalDelegate(ObtenerPerro);        &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en la segunda declaración (ad2): Aunque el delegate está declarado para métodos que devuelven un Animal podemos usar este delegate con métodos que devuelvan un Perro. Por eso decimos que los delegates son covariantes en C#.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Covarianza en arrays&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El siguiente código en C# funciona y es totalmente válido:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Animal[] animales = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro[100];&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es decir podemos asignar un array de Perros a un array de Animales. De nuevo los arrays son covariantes en C#. Esta decisión se tomó en su día para, bueno… luego hablaremos más sobre ella :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Covarianza en genéricos&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El siguiente código &lt;strong&gt;no compila&lt;/strong&gt; en C#:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List&amp;lt;ConsoleApplication8.Perro&amp;gt;' to 'System.Collections.Generic.List&amp;lt;ConsoleApplication8.Animal&amp;gt;'&lt;/span&gt;&lt;br /&gt;List&amp;lt;Animal&amp;gt; animales = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es por ello que decimos que los &lt;strong&gt;genéricos NO son covariantes en C#&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y ahora viene la pregunta… ¿por que?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien, recordad que si yo quiero sustituir un tipo D por otro tipo B eso significa que en un objeto de tipo D &lt;em&gt;debo poder hacer cualquier cosa que haga en un objeto de tipo B&lt;/em&gt;. Es decir, si hay algo, llamémosle f(), que pueda hacer para un objeto de tipo B que no pueda hacer con un objeto de tipo D, no puedo aplicar covarianza… Ya que entonces podría hacer D.f() que no sería válido (recordad que f() es válido para B y no para D).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Cojamos el caso de &lt;em&gt;List&amp;lt;Animal&amp;gt;&lt;/em&gt; y &lt;em&gt;List&amp;lt;Perro&amp;gt; &lt;/em&gt;(recordad que Perro deriva de Animal). La pregunta es… hay alqo que podemos hacer con List&amp;lt;Animal&amp;gt; y que NO podamos hacer con List&amp;lt;Perro&amp;gt;? Veamos…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Con List&amp;lt;Animal&amp;gt; puedo contar cuantos animales hay. Con List&amp;lt;Perro&amp;gt; también. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Con List&amp;lt;Animal&amp;gt; puedo obtener todos los Animales que hay. Con List&amp;lt;Perro&amp;gt; puedo obtener los Perros, pero dado que Perro deriva de Animal, si obtengo un Perro estoy obteniendo un Animal (primer ejemplo que hemos visto). Así pues ningún problema. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Con List&amp;lt;Animal&amp;gt; puedo añadir un Animal. Con List&amp;lt;Perro&amp;gt; puedo añadir… un Perro. Ojo que eso es importante: A List&amp;lt;Animal&amp;gt; puedo añadirle &lt;strong&gt;cualquier &lt;/strong&gt;Animal… puede ser un Perro, puede ser un Gato. A List&amp;lt;Perro&amp;gt; no puedo añadirle cualquier animal, &lt;em&gt;debe&lt;/em&gt; ser un Perro forzosamente. &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo tanto ya hemos encontrado que se puede hacer con List&amp;lt;Animal&amp;gt; que &lt;em&gt;no&lt;/em&gt; pueda hacerse con List&amp;lt;Perro&amp;gt;: Añadir un Gato.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si C# nos dejara aplicar covarianza entonces eso sería válido:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;List&amp;lt;Animal&amp;gt; animales = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;animales.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Gato());       &lt;span style="color: #008000"&gt;// EEehhh... estoy añadiendo un Gato a una lista de Perros?&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo tanto, para evitar eso y asegurar que las listas de perros sólo tendrán perros el compilador no nos deja hacer esa conversión: Los genéricos &lt;strong&gt;no&lt;/strong&gt; son covariantes.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y los arrays?&lt;/strong&gt; Recordáis que los arrays sí son covariantes. El siguiente código &lt;strong&gt;es válido&lt;/strong&gt; y legal:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Animal[] animal = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Perro[100];&lt;br /&gt;animal[0] = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Gato(); &lt;span style="color: #008000"&gt;// Un Gato en una jauría de Perros!&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si ejecutas el siguiente código obtendrás una &lt;a href="http://msdn.microsoft.com/en-us/library/system.arraytypemismatchexception.aspx"&gt;ArrayTypeMismatchException&lt;/a&gt; en tiempo de ejecución. Es decir el código compila pero luego rebienta.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Alguien podría decir que hubiesen aplicado eso mismo a las Listas… dejar que fuesen covariantes y luego rebentar en tiempo de ejecución si añado un Gato a una List&amp;lt;Perro&amp;gt;. Porque no lo han hecho así? Pues porque repetir errores no es nunca una buena solución. Los arrays jamás debieron haber sido covariantes. Si los crearon así fue para dar soporte a lenguajes tipo Java dentro del CLR (Java tiene arrays covariantes). Y así estamos: un error de diseño de Java propagado a .NET. Fijaos que eso obliga a que cada vez que añadimos un elemento en un array el CLR en tiempo de ejecución deba comprobar que el elemento &lt;em&gt;realmente&lt;/em&gt; es del tipo del array. Viva la eficiencia!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y con todo eso… llegó el Framework 4&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien… Ahora analicemos el siguiente código:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;Perro&amp;gt; JauriaDePerros()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;    IEnumerable&amp;lt;Animal&amp;gt; perritos = JauriaDePerros();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ya os lo avanzo: el siguiente código &lt;strong&gt;no compila con el Framework 3.5&lt;/strong&gt;. Recordad: los genéricos no son covariantes y hemos visto la razón. Pero &lt;em&gt;tiene&lt;/em&gt; sentido en este caso? Hay algo que pueda hacer con un IEnumerable&amp;lt;Animal&amp;gt; y que no pueda hacer con IEnumerable&amp;lt;Perro&amp;gt;? Veamos…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Con un IEnumerable&amp;lt;Animal&amp;gt; puedo obtener todos los Animales. Con un IEnumerable&amp;lt;Perro&amp;gt; puedo obtener todos los Perros, pero como hemos visto ya, los Perros los puedo ver como Animales. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y ya está. No puedo hacer nada más con un IEnumerable&amp;lt;&amp;gt; salvo obtener sus elementos. Entonces porque no compila el código en C#? Pues bien, porque pagan justos por pecadores: En el framework 3.5 los genéricos no son covariantes. Nunca, aunque &lt;em&gt;por lógica&lt;/em&gt; pudiesen serlo.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para tener una solución a estos casos donde la covarianza tiene sentido, debemos usar el Framework 4 (VS2010). Una de las novedades que incorpora C# en esta versión es precisamente esta: covarianza de genéricos &lt;em&gt;en según que casos&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Veamos: la covarianza en genéricos &lt;em&gt;es segura cuando el parámetro genérico se usa sólamente de salida&lt;/em&gt;. Es decir cuando &lt;em&gt;ningún método acepta ningún parámetro del tipo genérico, como mucho sólo lo devuelven&lt;/em&gt;. El problema en el caso de List&amp;lt;&amp;gt; estaba en que podía añadir un Gato a una lista de Perros. Y eso es posible porque uno de los métodos de la clase List&amp;lt;T&amp;gt; es Add(T item). Es decir el tipo genérico se usa como valor de entrada a los métodos. En cambio con IEnumerable&amp;lt;T&amp;gt; hemos visto que no hay ningún problema: En un IEnumerable&amp;lt;T&amp;gt; sólo puedo obtener sus elementos, pero no puedo añadirle elementos nuevos. No hay ningún método que reciba un parámetro del tipo genérico. Como mucho hay métodos que devuelven ojetos del tipo genérico. En este caso la covarianza es segura.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para indicar en C# 4.0 que una clase genérica es covariante respecto a su tipo genérico, usamos la palabra clave &lt;em&gt;out. &lt;/em&gt;P.ej. IEnumerable&amp;lt;T&amp;gt; en C# 4.0 está definido como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;out&lt;/span&gt; T&amp;gt; : IEnumerable&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Métodos...&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en el uso de &lt;em&gt;out&lt;/em&gt; para indicarle al compilador: Este tipo es covariante respecto al tipo genérico T. Entonces &lt;strong&gt;este código que en VS2008 no compilaba, es válido en C# 4.0&lt;/strong&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;Perro&amp;gt; JauriaDePerros()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;    IEnumerable&amp;lt;Animal&amp;gt; perritos = JauriaDePerros();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por supuesto, esto sigue sin compilar:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; List&amp;lt;Perro&amp;gt; JauriaDePerros()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;    List&amp;lt;Animal&amp;gt; perritos = JauriaDePerros();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ya que List&amp;lt;T&amp;gt; no es covariante respecto al tipo genérico T (lógico, si lo fuese podría añadir un Gato a una lista de Perros).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En cambio eso &lt;strong&gt;si que es correcto en VS2010&lt;/strong&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; List&amp;lt;Perro&amp;gt; JauriaDePerros()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Perro&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;    IEnumerable&amp;lt;Animal&amp;gt; perritos = JauriaDePerros();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Aunque el método JauriaDePerros() devuelve una List&amp;lt;Perro&amp;gt;, el código funciona porque:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;List&amp;lt;T&amp;gt; implementa IEnumerable&amp;lt;T&amp;gt; &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;IEnumerable&amp;lt;T&amp;gt; es covariante respecto a T &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En el fondo, fijaos que no hay problema: con &lt;em&gt;perritos&lt;/em&gt; lo único que puede hacerse es obtener sus elementos, así que de nuevo no hay peligro de que añada un Gato a &lt;em&gt;perritos&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Declaración de mis clases genéricas covariantes&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Si yo creo una clase que quiera que sea covariante con su tipo genérico, simplemente debo usar &lt;em&gt;out&lt;/em&gt;. La única restricción es que &lt;strong&gt;ningún método de mi clase podrá aceptar un parámetro del tipo genérico&lt;/strong&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; Foo&amp;lt;&lt;span style="color: #0000ff"&gt;out&lt;/span&gt; T&amp;gt;&lt;br /&gt;{&lt;br /&gt;    T Bar() { ... }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Baz(T t) { ... }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Este código no compila (&lt;em&gt;error CS1961: Invalid variance: The type parameter 'T' must be contravariantly valid on 'ConsoleApplication5.Foo&amp;lt;T&amp;gt;.Baz(T)'. 'T' is covariant.&lt;/em&gt;). Ese mensaje de error largote lo único que quiere decir es que T es covariante, y por lo tanto no podemos aceptar parámetros de tipo T.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finalmente tened presente que sólo las interfaces pueden declarar que su tipo genérico es covariante (las clases no).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bueno… dejémoslo aquí. Hay otro termino ligado a la covarianza que es la contravarianza, aunque no es tan &lt;em&gt;común&lt;/em&gt; como la covarianza y quizá algún día hablemos de ella :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo y recordaros lo que digo siempre en los posts de esta serie: Si tenéis temas sobre el lenguaje C# que queráis tratar, hacédmelo saber y haré lo que pueda!!!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Para variar, eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/"&gt;mi blog en geeks.ms&lt;/a&gt;! Pásate por allí que somos más!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-4784148144314985399?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/4784148144314985399/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=4784148144314985399' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4784148144314985399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4784148144314985399'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/c-basico-covarianza-en-genericos.html' title='C# Básico: Covarianza en genéricos'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8377336269549914891</id><published>2010-11-12T12:44:00.001+01:00</published><updated>2010-11-12T12:44:56.769+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Saca tus scripts de tu código HTML</title><content type='html'>&lt;p&gt;Buenas! En el post anterior os comenté el soporte de &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/11/09/unobtrusive-ajax-en-mvc3.aspx"&gt;Unobtrusive Ajax en ASP.NET MVC3&lt;/a&gt;. Hoy quiero mostraros que esa técnica &lt;strong&gt;ni&lt;/strong&gt; es exclusiva de MVC3, &lt;strong&gt;ni&lt;/strong&gt;&amp;#160; requiere HTML5 para nada. En fin, que podéis empezar a usarla ya, con independencia de la tecnología que uséis. Lo que contaré en este artículo no es nada “revolucionario” ni una “técnica nueva”…&lt;/p&gt;  &lt;p&gt;De hecho, el ejemplo va a ser una página HTML, nada de ASP.NET :)&lt;/p&gt;  &lt;p&gt;Veamos, la técnica de Unobtrusive Javascript, se refiere a &lt;strong&gt;no tener mezclado código javascript con código de marcado HTML&lt;/strong&gt;. Es decir, &lt;strong&gt;no&lt;/strong&gt; queremos algo como:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;txtName&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;onkeypress&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;checkKey();&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Aquí estamos mezclando código HTML con el código javascript (la llamada checkKey en el &lt;em&gt;onkeypress&lt;/em&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Imaginemos que queremos que nuestros &lt;strong&gt;textboxes sólo acepten números&lt;/strong&gt;. Y recordad que el objetivo es no tener código javascript mezclado con nuestro código HTML.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Eso lo podemos conseguir fácilmente, ya con jQuery:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;html xmlns=&lt;span style="color: #006080"&gt;&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Demo Unobtrusive Javascript&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;jquery-1.4.1.js&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;script type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;        $(document).ready(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; () {&lt;br /&gt;            $(&lt;span style="color: #006080"&gt;'input:text'&lt;/span&gt;).keypress(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;) {&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.keyCode &amp;lt; 47 || &lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.keyCode &amp;gt; 58) {&lt;br /&gt;                    &lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.preventDefault();&lt;br /&gt;                }&lt;br /&gt;            });&lt;br /&gt;        });&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;    Introduce sólo números: &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Incluso, si no queréis que haya el tag &amp;lt;script&amp;gt; con todo el código, podemos moverlo a un .js separado y usarlo desde nuestra página HTML que entonces quedaría como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;html xmlns=&lt;span style="color: #006080"&gt;&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Demo Unobtrusive Javascript&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;jquery-1.4.1.js&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;myscript.js&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    Introduce sólo números: &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo tanto vemos que con jQuery es muy fácil asignar comportamiento a objetos DOM, sin necesidad de andar con los handlers onXXXX.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora bien, el código jQuery selecciona &lt;strong&gt;todos&lt;/strong&gt; los &amp;lt;input type=”text”&amp;gt;, que passa si sólo quiero seleccionar &lt;em&gt;algunos?&lt;/em&gt; Como le indico a mi código jQuery que sólo algunos textboxes son numéricos?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Una solución es &lt;em&gt;invertarnos&lt;/em&gt; un atributo que indique que elementos queremos como numéricos. De esta manera p.ej. la página HTML queda como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;html xmlns=&lt;span style="color: #006080"&gt;&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Demo Unobtrusive Javascript&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;jquery-1.4.1.js&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;myscript.js&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    Introduce sólo números: &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; datatype=&lt;span style="color: #006080"&gt;&amp;quot;numeric&amp;quot;&lt;/span&gt; /&amp;gt;  &amp;lt;br /&amp;gt;&lt;br /&gt;    Aquí puedes introducir lo que quieras: &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en el “datatype=”numeric” que es el atributo que me va a servir para decidir que textboxes son numéricos.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y el código de myscript.js queda como:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;$(document).ready(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; () {&lt;br /&gt;    $(&lt;span style="color: #006080"&gt;'input[datatype=numeric]'&lt;/span&gt;).keypress(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;) {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.keyCode &amp;lt; 47 || &lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.keyCode &amp;gt; 58) {&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.preventDefault();&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos, simplemente incluyendo “myscript.js” en cualquier página ya podemos declarar que un textbox es numérico &lt;em&gt;simplemente&lt;/em&gt; poniendo el atributo datatype=”numeric”.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora, si alguien hace otra librería javascript para textboxes numéricos &lt;strong&gt;si también usa este atributo para indicarlos &lt;/strong&gt;(ahí está el quid de la cuestión) simplemente cambiando el &amp;lt;script&amp;gt; para que en lugar de ir a myscript.js vaya a la nueva librería, ya tengo todo el cambio hecho… es decir, me he independizado del framework javascript que use.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Y por ahí por donde entra HTML5?&lt;/strong&gt; Pues bien, como eso de crearnos nuestros propios atributos está bien pero genera HTML que podríamos llamar &lt;em&gt;inválido&lt;/em&gt; (en el sentido de que estos atributos no forman parte de HTML), para HTML5 han decidido simplemente que todos estos atributos “inventados” empiecen por &lt;em&gt;data-&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lo “único” que dice al respecto HTML5 es: “&lt;em&gt;Hey, si tienes que invertarte un atributo para lo que sea, haz que su nombre empiece por data-. Todos los atributos que empiecen por data- son atributos inventados por alquien y deben ser ignorados a todos los efectos (salvo para quien lo haya inventado que hará con él lo que le plazca, claro&lt;/em&gt;). Ok, &lt;a href="http://www.w3.org/TR/2009/WD-html5-20090423/dom.html"&gt;también añade una API específica (element.dataset) para leer esos atributos&lt;/a&gt; (pero eso de momento no nos importa ya que no está soportada por la mayoría de navegadores).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por lo tanto, si en lugar de que mi atributo se llame datatype, hago que le llame data-datatype (p.ej. cualquier nombre que empiece por data-) ya lo tengo todo &lt;em&gt;HTML5 compliant!&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De hecho podéis hacer la prueba en &lt;a title="http://validator.w3.org/check" href="http://validator.w3.org/check"&gt;http://validator.w3.org/check&lt;/a&gt;. Entráis el código HTML de la página y lo validáis contra:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;HTML5 usando el atributo datatype=”numeric” y os dará &lt;strong&gt;error&lt;/strong&gt; (Attribute not allowed) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;HTML5 usando el atributo data-datatype=”numeric” y os validará correctamente. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Cualquier otra versión de HTML y os dará error en ambos casos. &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Por lo tanto fijaos que &lt;strong&gt;desde ya&lt;/strong&gt; podeis empezar a aplicar técnicas de “Unobtrusive Javascript”: no necesitáis HTML5 para nada, ni MVC3 ni nada y la &lt;em&gt;recompensa&lt;/em&gt; es un HTML mucho más claro y sencillo de ver!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mi opinión es que, gracias a que HTML5 ha definido un &lt;em&gt;espacio de nombres&lt;/em&gt; (data-) para los &lt;em&gt;atrbutos inventados&lt;/em&gt; empezaremos a ver, cada ves más, librerías de javascript que usarán esos atributos, y seguramente algunos de ellos terminarán siendo estándares de facto (si yo hago una librería de javascript para validación. pues intentaré usar los mismos atributos data- que use la librería que sea &lt;em&gt;líder&lt;/em&gt; en aquel momento, para compatibilizarme con ella).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por cierto, si vais a usar muchos atributos data- en vuestras páginas web, echadle un vistazo a este plugin de jQuery: &lt;a href="http://plugins.jquery.com/project/html5-dataset"&gt;HTML5 Dataset&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Nota: &lt;/strong&gt;El código de ese artículo lo he probado con IE9 y Firefox 3.6.10.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Esto es un crosspost de &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt; (como no…)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8377336269549914891?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8377336269549914891/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8377336269549914891' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8377336269549914891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8377336269549914891'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/saca-tus-scripts-de-tu-codigo-html.html' title='Saca tus scripts de tu código HTML'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-3947569904904188283</id><published>2010-11-09T11:56:00.001+01:00</published><updated>2010-11-09T11:56:44.506+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>Unobtrusive Ajax en MVC3</title><content type='html'>&lt;p&gt;Buenas! Una de las novedades más interesantes de MVC3 es el soporte para eso que se llama &lt;em&gt;Unobtrusive &lt;/em&gt;Ajax. La verdad es que no encuentro una buena traducción para Unobtrusive (discreto no me convence).&lt;/p&gt;  &lt;p&gt;La idea del Unobtrusive Ajax es &lt;strong&gt;evitar mezclar código script con código HTML&lt;/strong&gt;. De la misma manera que CSS nos permite separar completamente el código HTML de su representación, con Unobtrusive Ajax vamos a poder separar el código javascript del código HTML.&lt;/p&gt;  &lt;p&gt;Pero mejor, veamoslo con un ejemplo, ultra sencillo :)&lt;/p&gt;  &lt;p&gt;Imaginad que tengo una vista con este contenido:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;h2&amp;gt;Normal Ajax&amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;% &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (Ajax.BeginForm(&lt;span style="color: #006080"&gt;&amp;quot;PostData&amp;quot;&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AjaxOptions() { HttpMethod=&lt;span style="color: #006080"&gt;&amp;quot;Post&amp;quot;&lt;/span&gt;, UpdateTargetId=&lt;span style="color: #006080"&gt;&amp;quot;datadiv&amp;quot;&lt;/span&gt;})) { %&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;label &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;=&lt;span style="color: #006080"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&amp;gt;Name: &amp;lt;/label&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; name=&lt;span style="color: #006080"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; id=&lt;span style="color: #006080"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;/&amp;gt;&lt;br /&gt;    &amp;lt;input type=&lt;span style="color: #006080"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; value=&lt;span style="color: #006080"&gt;&amp;quot;Send&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;% } %&amp;gt;&lt;br /&gt;&amp;lt;hr /&amp;gt;&lt;br /&gt;Aquí irá el resultado: &amp;lt;p /&amp;gt;&lt;br /&gt;&amp;lt;div id=&lt;span style="color: #006080"&gt;&amp;quot;datadiv&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Esta vista genera un &amp;lt;form&amp;gt; con un campo de texto y envía los datos a una acción llamada “PostData” e incrusta el resultado de dicha acción (que será una vista parcial) en el div cuyo id es “datadiv”.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Este es el código HTML generado por esta vista en MVC2:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Normal Ajax&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt; &lt;span style="color: #ff0000"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;/Home/PostData&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;post&amp;quot;&lt;/span&gt; &lt;br /&gt;   &lt;span style="color: #ff0000"&gt;onclick&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));&amp;quot;&lt;/span&gt; &lt;br /&gt;   &lt;span style="color: #ff0000"&gt;onsubmit&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: &amp;amp;#39;Post&amp;amp;#39;, updateTargetId: &amp;amp;#39;datadiv&amp;amp;#39; });&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Name: &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Send&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;hr&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;Aquí irá el resultado: &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;datadiv&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en que en el tag &amp;lt;form&amp;gt; se le ha incrustado código javascript para gestionar el &lt;em&gt;onclick&lt;/em&gt; y el &lt;em&gt;onsubmit&lt;/em&gt; (para poder realizar el envío via ajax).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bien… y &lt;strong&gt;esta misma vista (idéntica) que código genera en MVC3?&lt;/strong&gt; Pues el siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Normal Ajax&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h2&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt; &lt;span style="color: #ff0000"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;/Home/PostData&amp;quot;&lt;/span&gt; &lt;br /&gt;   &lt;span style="color: #ff0000"&gt;data-ajax&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-ajax-method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Post&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-ajax-mode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;replace&amp;quot;&lt;/span&gt; &lt;br /&gt;   &lt;span style="color: #ff0000"&gt;data-ajax-update&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;#datadiv&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Name: &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Send&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;hr&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;Aquí irá el resultado: &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;datadiv&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que diferencia… No hay nada de javascript mezclado en el código. Todo es HTML. Simplemente al tag &amp;lt;form&amp;gt; se le añaden unos cuantos atributos (los que empiezan por data-ajax) que indican como se debe comportarse este formulario a nivel de Ajax.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y quien realiza “la magia”? Pues quien va a ser… nuestra amada jQuery, junto con una extensión de Microsoft (el fichero &lt;em&gt;jquery.unobtrusive-ajax.js&lt;/em&gt;)! Para que esto funciona teneis que añadir tanto jQuery como la extensión de MS (yo los pongo en la master):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;&amp;lt;%: Url.Content(&amp;quot;&lt;/span&gt;~/Scripts/jquery-1.4.1.js&lt;span style="color: #006080"&gt;&amp;quot;) %&amp;gt;&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&lt;span style="color: #006080"&gt;&amp;quot;&amp;lt;%: Url.Content(&amp;quot;&lt;/span&gt;~/Scripts/jquery.unobtrusive-ajax.js&lt;span style="color: #006080"&gt;&amp;quot;) %&amp;gt;&amp;quot;&lt;/span&gt; type=&lt;span style="color: #006080"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Esta adaptación de los helpers en MVC3 para soportar esta característica es a lo que nos referimos cuando decimos que “ASP.NET MVC3 da soporte para &lt;em&gt;Unobtrusive&lt;/em&gt; Ajax”, y es una doble gran noticia. Digo doble porque por un lado nos permite seguir usando los helpers con la garantía de que vamos a generar código “limpio” de javascript y por otro lado &lt;strong&gt;el helper de Ajax usa ¡por fin! jQuery&lt;/strong&gt;. A diferencia de MVC2 donde el Helper Ajax usaba la Ajax Library de Microsoft. De hecho, aunque en los templates de proyecto se sigue poniendo, si me aceptas un consejo: bórrala y no la uses. Puedes borrarla con total tranquilidad porque en MVC3 ningún helper la usa.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Unobtrusive Ajax viene habilitado por defecto en los nuevos proyectos MVC3 pero lo podéis deshabilitar (y entonces generar el mismo código que en MVC2, usando la Microsoft Ajax Library). Podeis deshabilitarlo a nivel de vista o para todo el proyecto.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para deshabilitarlo a nivel de vista, basta con incluir:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;% HtmlHelper.UnobtrusiveJavaScriptEnabled = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;; %&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para deshabilitarlo para todo el proyecto, puedes incluir ese mismo código en el global.asax.cs o bien usar web.config:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;appSettings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;UnobtrusiveJavaScriptEnabled&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;appSettings&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lo mismo para habilitarlo. Si &lt;strong&gt;no&lt;/strong&gt; aparece la entrada &lt;em&gt;UnobtrusiveJavaScriptEnabled&lt;/em&gt; en el &amp;lt;appSettings&amp;gt; el valor por defecto es &lt;strong&gt;false&lt;/strong&gt;. Es por eso que si haces un upgrade de un proyecto de MVC2 a MVC3, no tendrás esta entrada en el web.config y por eso Unobtrusive Ajax estará deshabilitado!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: El hecho de que los atributos que se usan para que Unobtrusive Ajax funcione empiecen por “data-“ es porque HTML5 reserva estos atributos “para usos propios de los scripts del site”, tal y como podéis leer en la &lt;a href="http://dev.w3.org/html5/spec/elements.html#custom-data-attribute"&gt;especificación de Custom Data Attributes&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Para variar… otro crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;! ;-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-3947569904904188283?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/3947569904904188283/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=3947569904904188283' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/3947569904904188283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/3947569904904188283'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/unobtrusive-ajax-en-mvc3.html' title='Unobtrusive Ajax en MVC3'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-6644999214196201113</id><published>2010-11-08T11:29:00.001+01:00</published><updated>2010-11-08T11:29:47.866+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>How to: Obtener controles de un formulario con generics II (Linq al rescate).</title><content type='html'>&lt;p&gt;Ayer Lluis escribía este gran post: &lt;em&gt;&lt;a href="http://geeks.ms/blogs/lfranco/archive/2010/11/05/how-to-obtener-controles-de-un-formulario-con-generics.aspx"&gt;How to: Obtener controles de un formulario con generics&lt;/a&gt;&lt;/em&gt;. Como bien dice es una pregunta… recurrente en todos los sitios :)&lt;/p&gt;  &lt;p&gt;Lo bueno de eso del desarrollo es que para todo hay varias soluciones, así que aquí os propongo otra, pero usando Linq. Personalmente me encanta Linq, supongo que es porqué siempre me han fascinado los lenguajes funcionales…&lt;/p&gt;  &lt;p&gt;Antes que nada tenemos que solucionar un temilla: Linq funciona sobre IEnumerable&amp;lt;T&amp;gt; pero la propiedad Controls de un Control devuelve un objeto de tipo ControlCollection (otra de esas n-mil clases que no tienen sentido alguno y que existen sólo porque no teníamos generics en la versión 1 del framework). Así que el primer paso es obtener un IEnumerable&amp;lt;Control&amp;gt; a partir de una ControlCollection. Con un método extensor eso es trivial:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;Control&amp;gt; AsEnumerable (&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Control.ControlCollection @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var control &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (Control)control;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ale… listos, con eso &lt;em&gt;transformamos&lt;/em&gt; la CollectionControl en un IEnumerable&amp;lt;Control&amp;gt; y tenemos acceso a todo el potencial de Linq… Y como queda el método para obtener todos los controles de un tipo? Pues así:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; GetAllControls&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Control @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T : Control&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Controls.AsEnumerable().Where(x =&amp;gt; x.GetType() == &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T)).&lt;br /&gt;        Select(y=&amp;gt;(T)y).&lt;br /&gt;        Union(@&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Controls.AsEnumerable().SelectMany(x =&amp;gt; GetAllControls&amp;lt;T&amp;gt;(x)).&lt;br /&gt;        Select(y=&amp;gt;(T)y));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;¡No me diréis que no es precioso: no hay bucles, no hay ifs… Os he dicho que me encanta Linq? ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Hay una &lt;em&gt;pequeña&lt;/em&gt; diferencia entre la versión de Lluís y esta mía: la versión de Lluís usa una List&amp;lt;Control&amp;gt; en la que añade todas las referencias (copia las referencias a la lista. Ojo: las referencias, no los controles). Esa versión que usa Linq, no copia las referencias en ningún sitio, sinó que &lt;em&gt;simplemente&lt;/em&gt; itera sobre la coleccion original: no crea listas internas, ni nada… Ese es el poder de Linq!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es cierto que al usar IEnumerable&amp;lt;T&amp;gt; como valor de retorno, perdemos el método ForEach() (puesto que IEnumerable&amp;lt;T&amp;gt; no lo tiene y Linq no lo proporciona), pero hacer un método ForEach es trivial:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ForEach&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;, Action&amp;lt;T&amp;gt; action)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (T t &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        action(t);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;De todos modos, si os preguntáis &lt;strong&gt;porque Linq no ofrece un método ForEach&lt;/strong&gt; quizá deberíais leeros este post de Octavio: &lt;a href="http://geeks.ms/blogs/ohernandez/archive/2008/09/13/observaciones-con-respecto-al-m-233-todo-extensor-foreach-lt-t-gt.aspx"&gt;Observaciones con respecto a un método extensor ForEach&amp;lt;T&amp;gt;&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un&amp;#160; saludo a todos y gracias a Lluís por darme “la excusa” de hacer otro post! ;-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Eso es (como no) un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog de geeks.ms&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-6644999214196201113?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/6644999214196201113/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=6644999214196201113' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6644999214196201113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/6644999214196201113'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/how-to-obtener-controles-de-un.html' title='How to: Obtener controles de un formulario con generics II (Linq al rescate).'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-4820601951121033527</id><published>2010-11-03T10:54:00.001+01:00</published><updated>2010-11-03T10:54:30.172+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><title type='text'>Opinión: De si Silverlight está muerto, agonizante o mejor que nunca</title><content type='html'>&lt;p&gt;Andamos todos revolucionados estos dias, a raíz de unas declaraciones de &lt;a href="http://www.microsoft.com/presspass/exec/bobmuglia/"&gt;Bob Muglia&lt;/a&gt; donde decía “&lt;a href="http://www.zdnet.com/blog/microsoft/microsoft-our-strategy-with-silverlight-has-shifted/7834"&gt;Our strategy with Silverlight has shifted&lt;/a&gt;”. Eso unido al énfasis que se dio a HTML5 en el keynote del PDC y la no mención en absoluto de nada referente a Silverlight han disparado los rumores.&lt;/p&gt;  &lt;p&gt;Así pues… ¿está Silverlight muerto, agonizante o por el contrario está mejor que nunca? Primero un &lt;em&gt;disclaimer&lt;/em&gt;: este es un post de opinión, todo lo que yo afirmo tajantemente en este post son cosas que &lt;em&gt;yo&lt;/em&gt; creo. No tengo ni el conocimiento ni la razón absoluta, y además en MS nunca se sabe, así que como suele decirse: al final el tiempo dará y quitará razones :)&lt;/p&gt;  &lt;p&gt;La estrategia &lt;em&gt;inicial&lt;/em&gt; de Microsoft para posicionar Silverlight fue darle el nicho de aplicaciones web: Con Silverlight tus aplicaciones web tendrán una experiencia de usuario mejor, decían. En estos tiempos, comparar Silverlight con Flash era habitual, aunque Microsoft insistía en que no eran comparables: que Silverlight era para &lt;em&gt;aplicaciones completas&lt;/em&gt; y no para pequeños adornos. Cuando hacía tiempo que Flash había asumido que no sustituiría a HTML, parecía ser que Silverlight quería asumir el relevo.&lt;/p&gt;  &lt;p&gt;Pero con Silverlight 3 todo cambió: la posibilidad de ejecutar aplicaciones out-of-browser, la interoperabilidad COM y mejoras en el acceso a dispositivos locales, convertían a SL3 en algo distinto. Estaba claro que Silverlight llegaba a sitios donde HTML no sueña con llegar nunca. La batalla que inicialmente se libraba en el navegador ahora se trasladaba también al escritorio, y el rival era Adobe AIR. Habéis visto &lt;a href="http://seesmic.com/seesmic_desktop/sd2/"&gt;Seesmic Desktop 2&lt;/a&gt;? Es un excelente cliente de Twitter, para Windows y Mac, es una aplicación de escritorio… y está hecha con Silverlight.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;¿Y donde estamos ahora?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;El otro día en twitter &lt;em&gt;conversaba&lt;/em&gt; con &lt;a href="http://geeks.ms/blogs/amezcua"&gt;Alejandro Mezcua&lt;/a&gt; (&lt;a href="http://twitter.com/byteabyte"&gt;@byteabyte&lt;/a&gt;) y Dani Mora (&lt;a href="http://twitter.com/lodani"&gt;@LoDani&lt;/a&gt;) sobre el futuro de Silverlight. Yo argumentaba que &lt;strong&gt;no creo ni mucho menos que Silverlight&lt;/strong&gt; esté muerto. De hecho le veo un gran futuro a Silverlight en aplicaciones de escritorio y en aplicaciones para Windows Phone 7 (bueno, aquí depende de como le vaya a WP7, claro). Pero &lt;strong&gt;no le veo futuro para aplicaciones web&lt;/strong&gt;. Quiere decir esto que Silverlight va a desaparecer del browser? No, tiene su nicho en sites específicos donde HTML no llega: p. ej. nada mejor que Silverlight para streaming de video. Sí, sí… HTML5 va a soportar vídeo, pero no soportará DRM ni bitrates variables. Si necesitas esto, necesitarás &lt;em&gt;algo externo&lt;/em&gt; que te lo de, y ahí entra Silverlight. Pero para la creación &lt;em&gt;de aplicaciones web&lt;/em&gt;, no lo veo, y diría que Microsoft tampoco :)&lt;/p&gt;  &lt;p&gt;¿Y RIA? La clave de RIA es lo que significa la I. Dani me comentaba que para él, la I de RIA era “aquel entorno que el administrador de sistemas podía controlar”. Entonces &lt;em&gt;no &lt;/em&gt;estamos hablando de internet… llamésmole intranet o alguna otra cosa, pero no internet. Si quieres desarrollar una aplicación &lt;em&gt;para internet&lt;/em&gt; no hay mejor opción que HTML. Y los tiempos han cambiado mucho: de acuerdo que hace tiempo desarrollar con javascript era poco menos que un infierno, pero ahora tenemos a &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; que convierte eso en un juego de niños. Antes Ajax era doloroso y entraba con vaselina: ahora con un par de líneas puedes usar Ajax sin preocuparte de que navegadores se usan ni nada parecido. Y sí: hay &lt;a href="http://jquerymobile.com/"&gt;jQuery para dispositivos&lt;/a&gt; móviles. Aunque de todos modos la experiencia parece demostrar que en los móviles la gente prefiere aplicaciones nativas antes que webs.&lt;/p&gt;  &lt;p&gt;Así que si quieres estar presente en aplicaciones web dentro de poco tiempo, &lt;em&gt;aprende ya HTML5&lt;/em&gt;. No hagas caso de los que dicen que no está terminado, que no saldrá hasta dentro de no se cuantos años: son verdades a medias. Es cierto que la especificación no está lista, pero muchas partes ya estan terminadas, y ya están siendo implementadas en los navegadores. No ha salido hace poco la noticia de que &lt;a href="http://test.w3.org/html/tests/reporting/report.htm"&gt;IE9 era el navegador más compatible con HTML5&lt;/a&gt;? Como podría ser si no hubiese salido nada de HTML5? Dentro de poco ya comenzaremos a ver sites desarrollados en HTML5. El momento de lanzarse no es dentro de un, dos o tres años: es ahora.&lt;/p&gt;  &lt;p&gt;Pero seguiremos viendo Silverlight en el navegador? Pues creo que sí: en la gran internet en aquellos sitios &lt;em&gt;junto&lt;/em&gt; a HTML, donde se requieran aspectos que HTML5 no va asumir y en intranets (o entornos controlados) también supongo que podrán verse… Aunque en estos entornos, porque obligar al usuario a usar un navegador? Las capacidades out of browser de Silverlight hacen que el usuario tenga la sensación de usar una aplicación nativa, con toda la seguridad del sandbox de Silverlight y la misma facilidad de actualización que si una aplicación web se tratara.&lt;/p&gt;  &lt;p&gt;Y fuera del navegador? Pues sin duda. Veremos cada vez más aplicaciones de escritorio desarrolladas en Silverlight, y tener todas sus ventajas: actualizaciones automáticas, seguridad y multiplataforma (Windows, Mac). Y ojalá Microsoft se lance en serio a Linux y haga su implementación de Silverlight (y no lo deje medio abandonado con &lt;a href="http://www.mono-project.com/Moonlight"&gt;Moonlight&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;De hecho, para resumir este post, si hay alguien que deba sentirse amenazado por Silverlight no es ni mucho menos HTML5… en todo caso, si hemos de buscar a alguien, se trataría de WPF. Cada versión de Silverlight acorta distancias con &lt;em&gt;su hermano mayor&lt;/em&gt; y no es descabellado pensar si algún dia llegarán a &lt;em&gt;unirse&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Y a vosotros que os parece?&lt;/p&gt;  &lt;p&gt;Un saludo!&lt;/p&gt;  &lt;p&gt;PD: Como siempre… esto es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-4820601951121033527?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/4820601951121033527/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=4820601951121033527' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4820601951121033527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/4820601951121033527'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/11/opinion-de-si-silverlight-esta-muerto.html' title='Opinión: De si Silverlight está muerto, agonizante o mejor que nunca'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8424914747797506240</id><published>2010-10-07T14:28:00.001+02:00</published><updated>2010-10-07T14:28:45.123+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC3 Beta: Mis impresiones</title><content type='html'>&lt;p&gt;Buenooo… ayer fue un día movidito en Microsoft: &lt;a href="http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net-mvc-3-beta-and-webmatrix-beta-2.aspx"&gt;anunciaron de golpe&lt;/a&gt; la beta 2 de WebMatrix, la beta de MVC3 y un gestor de paquetes OSS para Visual Studio llamado NuPack. También he visto a través del &lt;a href="http://www.microsoft.com/web/downloads/platform.aspx"&gt;Web PI&lt;/a&gt; que está la CTP2 de Compact SQL 4.&lt;/p&gt;  &lt;p&gt;MVC1 salió con 5 (creo) previews antes de la beta, con MVC2 juraria que hicieron un par o tres, y con MVC3 sólo un preview1 y luego ya la beta… a ese ritmo MVC4 cuando salga lo hará ya con el SP1 incorporado. :P Esos de Microsoft van cada vez más rápido.&lt;/p&gt;  &lt;p&gt;Bueno, aquí van un poco mis impresiones sobre la Beta 3 de MVC :)&lt;/p&gt;  &lt;p&gt;Me centraré básicamente en lo que ha cambiado desde la preview1 hasta la Beta.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. Creación de aplicaciones&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Cuando le damos a nuevo proyecto en el Visual Studio, nos sale &lt;em&gt;una sola&lt;/em&gt; opción de MVC3:&amp;#160; ASP.NET MVC 3 Web Application y una vez la seleccionamos es cuando nos deja elegir si queremos una aplicación vacía o la estándard (con los controladores Account y Home) y que View Engine queremos usar. Son las mismas opciones que teníamos en MVC2 (excepto lo del view engine) pero mejor organizadas.&lt;/p&gt;  &lt;p&gt;Pero vamos… nada nuevo bajo el sol :D&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2. Donde está IServiceLocator?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;En &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/07/28/asp-net-mvc-3-preview-1.aspx"&gt;mi post sobre la preview1&lt;/a&gt; comentaba que el soporte para IoC se basaba en la interfaz &lt;a href="http://commonservicelocator.codeplex.com/"&gt;IServiceLocator&lt;/a&gt;, un proyecto de codeplex para proporcionar una interfaz común a distintos contenedores IoC y así permitir independizarnos de ellos. Decía también que la Preview1 contenía una implementación propia de IServiceLocator en lugar de usar la del assembly que está en codeplex, pero que se esperaba que en la versión final eso no fuera así. &lt;/p&gt;  &lt;p&gt;Pues bien… al final eso ha cambiado un poco: Ahora, a través de la clase &lt;em&gt;DependencyResolver&lt;/em&gt; podemos indicar a MVC3 que debe usar para resolver sus dependencias. Y tenemos tres posibilidades:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Pasarle un objeto que implemente una interfaz nueva llamada &lt;em&gt;IDependencyResolver&lt;/em&gt; (propia de MVC3). Dicha interfaz está definida:       &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;       &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IDependencyResolver&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; GetService(Type serviceType);&lt;br /&gt;    IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; GetServices(Type serviceType);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;      &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Pasarle dos delegates, el primero del cual se corresponde al método GetService y el segundo al método GetServices &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Pasarle un object. En este caso el object &lt;em&gt;debe&lt;/em&gt; implementar la interfaz IServiceLocator. Pero (imagino que) ASP.NET MVC3 invocará los métodos via reflection, por lo que &lt;em&gt;cualquier&lt;/em&gt; IServiceLocator vale, no es necesario usar el assembly de codeplex. Supongo que es para evitar tener una dependencia de MVC3 hacia un assembly “externo”. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Veamos un ejemplo:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;P.ej. si usásemos Unity podríamos crear un IDependencyResolver propio:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnityDependencyResolver : IDependencyResolver&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; IUnityContainer _ctr;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnityDependencyResolver(IUnityContainer ctr)&lt;br /&gt;    {&lt;br /&gt;        _ctr = ctr;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; GetService(Type serviceType)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _ctr.Resolve(serviceType);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; GetServices(Type serviceType)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _ctr.ResolveAll(serviceType);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y registrarlo en el global.asax:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;UnityContainer ctr = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityContainer();&lt;br /&gt;DependencyResolver.SetResolver(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityDependencyResolver(ctr));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Guay! Pero también podríamos usar la versión que admite un object y pasarle una implementación de IServiceLocator. La versió 2.0 de Unity ya viene con el assembly del service locator incorporado y un adaptador creado (si usais versiones anteriores de Unity os podéis &lt;a href="http://commonservicelocator.codeplex.com/"&gt;descargar tanto la implementación de IServiceLocator como el adaptador para Unity desde codeplex&lt;/a&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En nuestro caso nos basta con agregar una referencia al ensamblado &lt;em&gt;Microsoft.Practices.ServiceLocation.dll&lt;/em&gt; (que viene con Unity o os habéis descargado de codeplex) y usar:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;UnityContainer ctr = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityContainer();&lt;br /&gt;DependencyResolver.SetResolver(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityServiceLocator(ctr));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;(Si usáis una versión de Unity anterior a la 2.0 necesitaréis también una referencia a &lt;em&gt;Microsoft.Practices.Unity.ServiceLocatorAdapter.dll&lt;/em&gt; que también os habréis descargado de codeplex).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Listos! Con esto MVC3 ya usará nuestro DependencyResolver para crear los controladores, así que ya podremos inyectarles dependencias (fijaos que no ha sido necesario crear una factoría propia como hacíamos en MVC2).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;3. IControllerActivator&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;IControllerActivator es una interfaz nueva de MVC3 cuya responsabilidad es devolver una instancia de un controlador de un determinado tipo. Antes esa responsabilidad era &lt;em&gt;una más&lt;/em&gt; de las responsabilidades de la factoría de controladores: cuando en MVC2 queríamos usar DI generalmente implementábamos una factoría propia &lt;em&gt;derivada&lt;/em&gt; de &lt;em&gt;DefaultControllerFactory &lt;/em&gt;y refefiniamos el método GetControllerInstance:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;P.ej. esa sería una factoría de controladores para usar IServiceLocator en MVC2:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ServiceLocatorControllerFactory : DefaultControllerFactory&lt;br /&gt; {&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; IServiceLocator _sl;&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ServiceLocatorControllerFactory(IServiceLocator sl) &lt;br /&gt;     {&lt;br /&gt;         _sl = sl;&lt;br /&gt;     }&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IController GetControllerInstance(RequestContext requestContext, Type controllerType)&lt;br /&gt;     {&lt;br /&gt;         IController controller = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br /&gt;         controller = _sl != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ?  _sl.GetInstance(controllerType) &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; IController : &lt;br /&gt;             &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.GetControllerInstance(requestContext, controllerType);&lt;br /&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; controller;&lt;br /&gt;     }&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En MVC3 han separado los dos comportamientos: Por un lado el decidir &lt;em&gt;que&lt;/em&gt; tipo de controlador instanciar se queda en la factoría de controladores y por otro lado &lt;em&gt;instanciar&lt;/em&gt; el controlador es responsabilidad de &lt;em&gt;IControllerActivator&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El uso de IControllerActivator nos permite definir &lt;em&gt;como&lt;/em&gt; se crean nuestros controladores. Si no hay ningún IControllerActivator MVC3 usará el DependencyResolver (así que &lt;strong&gt;no&lt;/strong&gt; es necesario implementar IControllerActivator sólo para DI). Si no hay DependencyResolver pues supongo que usará Reflection.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Como MVC3 busca las cosas en varios sitios podemos pasarle el IControllerActivator a la DefaultControllerFactory (tiene un parámetro que acepta un IControllerActivator) &lt;strong&gt;o bien&lt;/strong&gt;, registrarlo en el DependencyResolver. O sea podemos usar esto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// Registramos un singleton con nuestro IControllerActivator&lt;/span&gt;&lt;br /&gt;ctr.RegisterInstance&amp;lt;IControllerActivator&amp;gt;(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomControllerActivator());&lt;br /&gt;DependencyResolver.SetResolver(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityServiceLocator(ctr));&lt;br /&gt;&lt;span style="color: #008000"&gt;// No registramos IControllerFactory por lo que se usará la DefaultControllerFactory&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;O bien esto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// Registramos la DefaultControllerFactory como la factoría a usar&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// pasándole el IControllerActivator deseado&lt;/span&gt;&lt;br /&gt;ctr.RegisterInstance&amp;lt;IControllerFactory&amp;gt;&lt;br /&gt;    (&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DefaultControllerFactory(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomControllerActivator()));&lt;br /&gt;DependencyResolver.SetResolver(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityServiceLocator(ctr));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pero &lt;strong&gt;ambas&lt;/strong&gt; cosas a la vez no (os dará error).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;4. Nuevos Helpers&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bueno, ahora tenemos un conjunto de &lt;em&gt;Helpers&lt;/em&gt; nuevos (bueno, nuevos para MVC, porque ya estaban en WebMatrix). Para usar esos helpers basta con agregar una referencia a System.Web.Helpers (viene ya por defecto):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&amp;lt;div&amp;gt;&lt;br /&gt;    El Hash de eiximenis es: @Crypto.Hash(&lt;span style="color: #006080"&gt;&amp;quot;eiximenis&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Diria que &lt;strong&gt;no&lt;/strong&gt; están disponibles todos los helpers que hay en WebMatrix… Espero que en la versión final sí estén todos, porque hay algunos que son una pasada!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;5. Ajax no “obtrusivo” (unobtrusive)&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El helper Ajax de MVC3 puede generar código Ajax que &lt;strong&gt;no&lt;/strong&gt; está mezclado con el código HTML, aprovechando jQuery y una de las nuevas capacidades de HTML5… P.ej. el siguiente código en una vista:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;@Ajax.ActionLink(&lt;span style="color: #006080"&gt;&amp;quot;Pulsa aquí para modif el DIV&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;AjaxAction&amp;quot;&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AjaxOptions() { UpdateTargetId=&lt;span style="color: #006080"&gt;&amp;quot;mydiv&amp;quot;&lt;/span&gt;})&lt;br /&gt;&amp;lt;div id=&lt;span style="color: #006080"&gt;&amp;quot;mydiv&amp;quot;&lt;/span&gt;&amp;gt;Div a modificar&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Nos genera el código HTML:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;a&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-ajax&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-ajax-mode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;replace&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;data-ajax-update&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;#mydiv&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;href&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;/Home/AjaxAction&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Pulsa aqu&amp;amp;#237; para modif el DIV&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;a&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;mydiv&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Div a modificar&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que hay atributos “&lt;em&gt;data-ajax-*“ &lt;/em&gt;que son interpretados por jQuery para realizar las acciones: de esa manera no hay ninguna llamada a ningún script mezclado con el código. Los atributos que empiezan por “data-“ son considerados especiales en HTML5 (&lt;a href="http://www.javascriptkit.com/dhtmltutors/customattributes.shtml"&gt;custom HTML5 attributes&lt;/a&gt;): HTML5 no admite que pongamos nuestros propios atributos a no ser que empiecen por data-. Esto permite separar el comportamiento (definiendolo en estos atributos especiales) del código.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;6. Soporte para Razor&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pues… sigue bajo mínimos… Es decir, Razor está totalmente soportado en run-time (y ahora con sintaxis VB.NET también!) pero para VS2010 Razor sigue sin existir. Las vistas .cshtml (o .vbhtml) no tienen ni sintaxis coloreada ni tampoco intellisense. Pero es que ni tan siquiera las reconoce como HTML (o sea ni tenemos intellisense de HTML tampoco).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Al margen de esto hay algunas novedades menores para Razor como el soporte de @model para definir el modelo, pero vamos… nada excepcionalmente nuevo.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;7. Conclusiones&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Las dos grandes novedades de esta Beta, respecto a la preview1, son algunas mejoras más en la inyección de dependencias (DependencyResolver, IControllerActivator) y el soporte para ajax no “obtrusivo”. El resto son mejoras menores (aunque interesantes).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Sigo pensando que, del mismo modo que se llama MVC3 se podría llamar MVC2.5, porque no hay cambios espectacularmente grandes (excepto Razor, pero es &lt;em&gt;simplemente&lt;/em&gt; otro ViewEngine, como muchos más que ya existían). Eso no es necesariamente malo: el framework ya está alcanzando cierto grado de madurez.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para finalizar, leeros las &lt;a href="http://www.asp.net/learn/whitepapers/mvc3-release-notes"&gt;release notes de la beta de MVC3&lt;/a&gt; donde se enumeran las novedades!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Para variar… esto es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;!!!!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8424914747797506240?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8424914747797506240/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8424914747797506240' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8424914747797506240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8424914747797506240'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/10/aspnet-mvc3-beta-mis-impresiones.html' title='ASP.NET MVC3 Beta: Mis impresiones'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-3001855498517263974</id><published>2010-10-06T12:08:00.001+02:00</published><updated>2010-10-06T12:08:29.827+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server compact'/><title type='text'>SQL Server Compact 4: Unable to load the native components</title><content type='html'>&lt;p&gt;Buenas! Un post ligerito, ligerito :)&lt;/p&gt;  &lt;p&gt;Ando esos días probando cosillas con SQL Server Compact 4 (que os podéis descargar desde &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=0d2357ea-324f-46fd-88fc-7364c80e4fdb&amp;amp;displaylang=en"&gt;su página de descargas&lt;/a&gt; o bien usando &lt;a href="http://www.microsoft.com/web/downloads/platform.aspx"&gt;Web Platofrm Installer&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;Habiendo probado código con &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=4e094902-aeff-4ee2-a12d-5881d4b0dd3e&amp;amp;displaylang=en"&gt;EF 4 Code First&lt;/a&gt; que estaba funcionando bien, empecé otras pruebas usando el proveedor propio de ADO.NET. Así que agregué una referencia a la &lt;em&gt;System.Data.SqlServerCe.dll&lt;/em&gt; que viene con SQL Server Compact 4, y cree una conexión:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;SqlCeConnection con = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlCeConnection()&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pues bien, al crear la conexión (fijaos que aquí no hay cadena de conexión, todavía no me conecto a ningún .sdf) ya me salta una &lt;em&gt;SqlCeException&lt;/em&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;Unable to load the native components of SQL Server Compact corresponding to the ADO.NET provider of version 8402. Install the correct version of SQL Server Compact. Refer to KB article 974247 for more details.&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Hombre, es de agradecer que la propia excepción te diga un KB que consultar, así que ni corto ni perezoso me dirigo al &lt;a href="http://support.microsoft.com/kb/974247"&gt;KB974247&lt;/a&gt;, pero nada de lo que dice es aplicable en mi caso.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Descartando el hecho de que sea una mala instalación (puesto que con EF 4 Code First era capaz de conectarme) me puse a mirar que podría estar pasando… y la respuesta final es que &lt;strong&gt;se deben copiar los binarios de SQL Server Compact 4 a la carpeta bin&lt;/strong&gt; de la aplicación.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En mi caso SQL Server Compact 4 se ha instalado en &lt;em&gt;C:\Program Files\Microsoft SQL Server Compact Edition\v4.0&lt;/em&gt; y los binarios que he copiado son las carpetas &lt;em&gt;x86&lt;/em&gt; y &lt;em&gt;amd64&lt;/em&gt; que están en la carpeta &lt;em&gt;Private&lt;/em&gt;. De hecho en mi caso me basta con la carpeta x86 puesto que mi máquina es de 32 bits.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Así pues en el bin/Debug de mi aplicación tengo mi aplicación, la &lt;em&gt;System.Data.SqlServerCe.dll&lt;/em&gt; y la carpeta x86 con los binarios de SQL Server Compact 4.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y entonces me funciona todo correctamente.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Y de regalo, os dejo (por si no lo conocíais) el enlace de &lt;a href="http://sqlcetoolbox.codeplex.com/"&gt;una extensión, llamada SqlCeToolbox, para vs2010 para poder tratar con ficheros .sdf de la versión 4&lt;/a&gt; (sinó la &lt;em&gt;otra&lt;/em&gt; manera que hay es usar WebMatrix que tiene un diseñador de tablas, pero me parece más potente esta exensión).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Y para variar… esto es un crosspsost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;!! ;-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-3001855498517263974?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/3001855498517263974/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=3001855498517263974' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/3001855498517263974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/3001855498517263974'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/10/sql-server-compact-4-unable-to-load.html' title='SQL Server Compact 4: Unable to load the native components'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8965527778820396042</id><published>2010-09-24T13:00:00.001+02:00</published><updated>2010-09-24T13:00:02.076+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unity'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='patrones'/><title type='text'>EF4 Code First, MVC2 y Unity para atarlo todo un poco…</title><content type='html'>&lt;p&gt;Buenas! No soy ni mucho menos un experto en EF (es más, me acabo de poner), como pueda serlo p.ej. &lt;a href="http://geeks.ms/blogs/unai/"&gt;Unai&lt;/a&gt;, pero desde que &lt;a href="http://weblogs.asp.net/scottgu/"&gt;Scott Guthrie&lt;/a&gt; publicó un &lt;a href="http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx"&gt;post sobre EF Code First&lt;/a&gt; he empezado a mirar algunas cosillas.&lt;/p&gt;  &lt;p&gt;Resumiendo rápidamente EF Code First nos permite desarrollar nuestra capa de acceso a datos codificando &lt;em&gt;primero&lt;/em&gt; las clases, clases que son &lt;a href="http://en.wikipedia.org/wiki/Plain_Old_CLR_Object"&gt;POCO&lt;/a&gt;. Eso nos permite conseguir lo que se conoce como &lt;em&gt;persistance ignorance&lt;/em&gt; (o que las clases que nos representan los datos sean agnósticas sobre cualquier tecnología de acceso a datos).&lt;/p&gt;  &lt;p&gt;Que quede claro que Code First &lt;strong&gt;no&lt;/strong&gt; es la única manera de usar objetos POCO en EF: Unai y Alberto hablan del tema &lt;a href="http://geeks.ms/blogs/unai/archive/2010/01/19/ef-4-0-poco-y-proxies-din-225-micos.aspx"&gt;aquí&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/adiazmartin/archive/2010/01/17/poco-en-entity-framework-4-0.aspx"&gt;aquí&lt;/a&gt;. Y dad por seguro que ellos conocen EF mucho más que yo :)&lt;/p&gt;  &lt;p&gt;Lo que os quiero comentar es como se puede montar EF Code First en una aplicación MVC2 para poder usar el patrón Repository y Unit Of Work, de forma que los controladores no deban saber nada del mecanismo subyacente de acceso a datos (es decir, los controladores ignoran completamente que están usando EF).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. Rápida, rapidísima introducción a EF Code First&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Usar EF Code First es muy sencillo. En el post de Scott Guthrie está todo explicado paso a paso, pero resumiendo podríamos decir que me puedo crear una clase tal que:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Persona&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; PersonaId {get; set;}&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Nombre {get; set;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Esta clase nos permitiría acceder a datos almacenados en una tabla con los campos PersonaId y Nombre (EF Code First es capaz de crear la BBDD a partir del modelo de objetos). Para acceder a la bbdd creamos un objeto derivado de DbContext:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MyDatabase : DbContext&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DbSet&amp;lt;Persona&amp;gt; Personas {get; set;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y a partir de aquí instanciamos un objeto MyDatabase y lanzamos consultas linq contra la propiedad Personas… :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;2. Patrón repositorio y Unit of work&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Esos patrones están explicados por activa y por pasiva en muchos sitios. P.ej. aquí está el &lt;a href="http://martinfowler.com/eaaCatalog/repository.html"&gt;patrón repositorio&lt;/a&gt; y aquí el &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;Unit of Work&lt;/a&gt; (UoW). Básicamente entendemos que el repositorio es una colección de objetos en memoria y que el patrón UoW sincroniza todos los cambios hechos en memoria hacia la base de datos.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Supongamos estos dos interfaces para definir ambos patrones:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IRepository&amp;lt;TEntity&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; TEntity : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    IQueryable&amp;lt;TEntity&amp;gt; AsQueryable();    &lt;br /&gt;    IEnumerable&amp;lt;TEntity&amp;gt; GetAll();&lt;br /&gt;    IEnumerable&amp;lt;TEntity&amp;gt; Find(Expression&amp;lt;Func&amp;lt;TEntity, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IUnitOfWork&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Commit();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mi repositorio es de sólo lectura (no hay métodos Add ni Remove ni nada, pero todo es añadirlos) y el Unit of Work lo único que tiene es el método Commit() para sincronizar los cambios hechos en los repositorios y mandarlos todos a la base de datos.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;EF Code First, implementa de &lt;em&gt;per se&lt;/em&gt; el patrón Unit Of Work (a través de DbContext) y también el patrón repositorio a través de DbSet&amp;lt;&amp;gt;, pero recordad que yo quiero “agnostizarme” al respecto de EF, por eso creo las interfaces y ahora debo crear implementaciones de ellas &lt;em&gt;para EF&lt;/em&gt;:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repository&amp;lt;TEntity&amp;gt; : IRepository&amp;lt;TEntity&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; TEntity : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; IDbSet&amp;lt;TEntity&amp;gt; _dbSet;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Repository(IDbContext objectContext)&lt;br /&gt;    {&lt;br /&gt;        _dbSet = objectContext.Set&amp;lt;TEntity&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IQueryable&amp;lt;TEntity&amp;gt; AsQueryable()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _dbSet;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;TEntity&amp;gt; GetAll()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _dbSet.ToList();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;TEntity&amp;gt; Find(Expression&amp;lt;Func&amp;lt;TEntity, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _dbSet.Where(&lt;span style="color: #0000ff"&gt;where&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnitOfWork : IUnitOfWork, IDisposable&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; IDbContext _objectContext;&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnitOfWork(IDbContext objectContext)&lt;br /&gt;    {&lt;br /&gt;        _objectContext = objectContext;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_objectContext != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            _objectContext.Dispose();&lt;br /&gt;        }&lt;br /&gt;        GC.SuppressFinalize(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Commit()&lt;br /&gt;    {&lt;br /&gt;        _objectContext.SaveChanges();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La única “complicación” es en la implementación de &lt;em&gt;UnitOfWork&lt;/em&gt;, que en el constructor uso un objeto de tipo &lt;em&gt;IDbContext&lt;/em&gt;, pero esta interfaz &lt;strong&gt;no existe&lt;/strong&gt; en EF: me la he inventado yo, para poder realizar DI luego cuando use Unity. La interfaz IDbContext es muy simple:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IDbContext : IDisposable&lt;br /&gt;{&lt;br /&gt;    IDbSet&amp;lt;T&amp;gt; Set&amp;lt;T&amp;gt;() &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; SaveChanges();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Me permite obtener un &lt;em&gt;IDbSet&lt;/em&gt; de entidades de tipo T y el método &lt;em&gt;SaveChanges&lt;/em&gt; para persistir los cambios realizados en este contexto hacia la BBDD.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;3. Uso de todo esto…&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para usar directamente un repositorio me basta con instanciarlo, pasándole como parámetro el IDbContext. Pero recordad que la clase DbContext de EF Code First &lt;strong&gt;no&lt;/strong&gt; implementa IDbContext (que me lo he inventado yo), así que uso el patrón&lt;em&gt; &lt;a href="http://en.wikipedia.org/wiki/Adapter_pattern"&gt;Adapter&lt;/a&gt;&lt;/em&gt; para &lt;em&gt;traducir &lt;/em&gt;los objetos DbContext a IDbContext:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; DbContextAdapter : IDbContext&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; DbContext _context;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DbContextAdapter(DbContext context)&lt;br /&gt;    {&lt;br /&gt;        _context = context;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose()&lt;br /&gt;    {&lt;br /&gt;        _context.Dispose();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IDbSet&amp;lt;T&amp;gt; Set&amp;lt;T&amp;gt;() &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _context.Set&amp;lt;T&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; SaveChanges()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _context.SaveChanges();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora sí que ya puedo crear un repositorio:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;IDbContext ctx = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DbContextAdapter(MyDatabase);  &lt;span style="color: #008000"&gt;// MyDatabase deriva de DbContext&lt;/span&gt;&lt;br /&gt;var rep = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Repository&amp;lt;Persona&amp;gt;(ctx);&lt;br /&gt;var personas = rep.FindAll();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para usar el Unit of Work vinculado a un contexto haríamos lo mismo.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;4. Añadiendo IoC a todo esto…&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora que ya vemos como podemos usar nuestro repositorio, vamos a ver como Unity nos ayuda a tener IoC y independizarnos realmente de EF.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Primero podríamos registrar las implementaciones concretas de IRepository y IUnitOfWork:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #008000"&gt;// Container es el IUnityContainer&lt;/span&gt;&lt;br /&gt;Container.RegisterType(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(IRepository&amp;lt;&amp;gt;), &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Repository&amp;lt;&amp;gt;));&lt;br /&gt;Container.RegisterType&amp;lt;IUnitOfWork, UnitOfWork&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora debemos mapear IDbContext a DbContextAdapter (porque para instanciar tanto IRepository como IUnitOfWork les debemos pasar un IDbContext. Podríamos usar lo siguiente:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Container.RegisterType&amp;lt;IDbContext, DbContextAdapter&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Este RegisterType está bien, pero el problema nos viene cuando vemos que el constructor de DbContextAdapter tiene un objeto &lt;em&gt;DbContext&lt;/em&gt;. Eso significaría que Unity nos crearía un objeto de la clase &lt;strong&gt;DbContext&lt;/strong&gt; y no de la clase derivada MyDatabase, para instanciar los objetos DbContextAdapter. &lt;strong&gt;Nota:&lt;/strong&gt; Una solución sería que la clase DbContextAdapter tuviese en su constructor un objeto que no fuera DbContext sinó MyDatabase pero eso entonces limita la reutilización de todo lo que estamos haciendo!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por suerte no estamos perdidos! Unity incorpora un mecanismo mediante el cual le podemos decir &lt;em&gt;como crear&lt;/em&gt; un objeto de una determinada clase. &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/06/02/novedades-de-unity-2-0.aspx"&gt;En mi post sobre Unity 2.0&lt;/a&gt;, hablé de las Injection Factories. La idea es decirle a Unity que cuando necesite un objeto de la clase indicada, en lugar de crearlo tal cual use una factoría nuestra.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es decir podemos hacer una factoría para crear DbContext que en lugar de un DbContext devuelva un MyDatabase, y Unity usará dicha factoría cada vez que deba crear un DbContext:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Container.RegisterType&amp;lt;DbContext&amp;gt;(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; InjectionFactory(x =&amp;gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MyDatabase()));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Listos! Con esto cuando Unity deba pasar a DbContextAdapter un objeto DbContext (como indica el constructor) creará realmente un objeto MyDatabase.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Ahora si que ya puedo hacer:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var rep = Container.Resolve&amp;lt;IRepository&amp;lt;Persona&amp;gt;&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;5. Y finalmente… MVC2&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para integrar esto dentro de MVC2 es muy sencillo: como siempre que queramos inyectar IoC en los controladores lo que debemos tocar es… la factoría de controladores:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnityControllerFactory : DefaultControllerFactory&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; IUnityContainer _sl;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnityControllerFactory(IUnityContainer sl) &lt;br /&gt;    {&lt;br /&gt;        _sl = sl;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IController GetControllerInstance(RequestContext requestContext, Type controllerType)&lt;br /&gt;    {&lt;br /&gt;        IController controller = _sl.Resolve(controllerType);&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; controller;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y como siempre establecerla en el Global.asax:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;UnityControllerFactory slcf = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UnityControllerFactory(container);&lt;br /&gt;ControllerBuilder.Current.SetControllerFactory(slcf);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! Ahora si que hemos llegado al punto &lt;strong&gt;final&lt;/strong&gt;. Por fin podemos declarar un controlador tal que:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PersonasController : Controller&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; IRepository&amp;lt;Persona&amp;gt; _rep;&lt;br /&gt; &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HandController(IRepository&amp;lt;Persona&amp;gt; rep)&lt;br /&gt;    {&lt;br /&gt;        _rep = rep;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y empezar a trabajar usando el repositorio! :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que en este punto (el controlador) no tenemos nada que nos ate a EF: el repositorio es una interfaz y las clases que usa el repositorio son objetos POCO.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;6. Y para terminar (pero NO lo menos importante)…&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Cuando trabajamos con aplicaciones web, es recomendable que los contextos de base de datos tengan una duración (lifetime) de request (se les llama objetos per-request): es decir si durante una misma petición se necesitan dos repostorios, estos dos repositorios deben de compartir del contexto de base de datos. Con lo que tenemos ahora &lt;em&gt;no&lt;/em&gt; sucede esto, ya que cada vez que Unity deba crear un Repository&amp;lt;&amp;gt; creará su DbContextAdapter asociado que a su vez creará un DbContext (MyDatabase) &lt;strong&gt;nuevo&lt;/strong&gt;. Ese comportamiento no es el desado.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Por suerte Unity tiene un mecanismo muy bueno para poder establecer &lt;em&gt;cada cuando&lt;/em&gt; debe el contenedor crear un objeto de un tipo determinado: &lt;a href="http://geeks.ms/blogs/etomas/archive/2009/10/26/lifetime-managers-en-unity-o-191-como-s-233-que-eso-que-me-das-es-un-singleton.aspx"&gt;los lifetime managers&lt;/a&gt;. Una solución es crearse un HttpRequestLifetimeManager, de forma que los objetos sólo persistirán durante la misma petición y usar este lifetime manager cuando hagamos el RegisterType de DbContext.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;En &lt;a title="http://unity.codeplex.com/Thread/View.aspx?ThreadId=38588" href="http://unity.codeplex.com/Thread/View.aspx?ThreadId=38588"&gt;http://unity.codeplex.com/Thread/View.aspx?ThreadId=38588&lt;/a&gt; tenéis una implementación de un &lt;strong&gt;HttpRequestLifetimeManager&lt;/strong&gt;, junto con una interesante aportación sobre el uso (en su lugar) de contenedores hijos que mueran a cada request, que tengan los objetos registrados como singletons y eliminar el contenedor hijo (con Dispose()) al final de cada request. Esto tiene la ventaja de que se llamaría a Dispose() de los objetos contenidos (en esta segunda aproximación es el contendor hijo el que tiene un ciclo de vida per-request).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;7. Referencias&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Los siguientes posts contienen más información al respecto:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://elegantcode.com/2009/12/15/entity-framework-ef4-generic-repository-and-unit-of-work-prototype/"&gt;Entity Framework POCO (EF4): Generic Repository and Unit of Work Prototype&lt;/a&gt;. Este es el post que me ha servido de inspiración y de ayuda. Tiene una continuación (&lt;a href="http://elegantcode.com/2009/12/15/building-a-unity-extension-for-entity-framework-poco-configuration-repository-and-unit-of-work/"&gt;Unity Extension for Entity Framework POCO Configuration, Repository and Unit of Work&lt;/a&gt;) donde comenta el uso de Unity. Estos dos posts son &lt;strong&gt;de lectura imprescindible, &lt;/strong&gt;aunque por un lado haya tenido que modificar algunas cosillas para que funcione con la CTP4 de EF Code first y por otro en el tercer post utilize una StaticFactoryExtension en lugar de una Injection Factory (supongo que usa Unity 1.2 que no soporta Injection Factories). Este tercer post utiliza una aproximación &lt;strong&gt;genial&lt;/strong&gt; que es el uso de una extensión de Unity para configurar todos los mappings para los objetos de EF. Repito: lectura imprescindible. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Los posts de Scott Guthrie sobre EF Code First: &lt;br /&gt;    &lt;ol&gt;&lt;br /&gt;      &lt;li&gt;&lt;a title="http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx" href="http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx"&gt;http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx&lt;/a&gt; &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;      &lt;li&gt;&lt;a title="http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx" href="http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx"&gt;http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx&lt;/a&gt; &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;      &lt;li&gt;&lt;a title="http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx" href="http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx"&gt;http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx&lt;/a&gt; &lt;/li&gt;&lt;br /&gt;    &lt;/ol&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo!!! :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como no… esto es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas"&gt;mi blog en geeks.ms&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8965527778820396042?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8965527778820396042/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8965527778820396042' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8965527778820396042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8965527778820396042'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/09/ef4-code-first-mvc2-y-unity-para-atarlo.html' title='EF4 Code First, MVC2 y Unity para atarlo todo un poco…'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-8790813792291907995</id><published>2010-09-10T13:07:00.001+02:00</published><updated>2010-09-10T13:07:46.215+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>ASP.NET MVC – Formato de salida según Content-Type</title><content type='html'>&lt;p&gt;El otro día escribí un post donde vimos como &lt;a href="http://geeks.ms/blogs/etomas/archive/2010/09/09/asp-net-mvc-mostrar-datos-en-html-o-pdf-pero-en-el-fondo-vamos-a-hablar-de-la-tabla-de-rutas.aspx"&gt;mostrar una vista en PDF o HTML en función de una URL del tipo /controlador/accion(formato)/parámetros&lt;/a&gt;. El post estaba centrado básicamente en la tabla de rutas y cómo la URL clásica de ASP.NET MVC /Controlador/Accion/Parámetros no es una obligación sinó básicamente una convención.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.hadihariri.com/"&gt;Hadi Hariri&lt;/a&gt; realizó un comentario, muy interesante a mi jucio. Venía a decir que antes que añadir en la ruta el parámetro formato es mejor usar el campo &lt;em&gt;Accept&lt;/em&gt; de la request. Copio literalmente: “&lt;em&gt;La tercera opcion, que lo hace más transparente al usuario y además está en acorde a ReST, es la de usar las el ContentType en la petición, que es lo que yo normalmente hago.&lt;/em&gt;”&lt;/p&gt;  &lt;p&gt;Si quieres exponer una API lo más ReST posible en ASP.NET MVC y que tenga salidas en distintos formatos, sin duda deberías tener en cuenta la sugerencia de Hadi.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. La cabecera de la petición http&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Cuando un cliente envía una &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html"&gt;petición http&lt;/a&gt; a un servidor, que contiene &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"&gt;una cabecera con varios parámetros&lt;/a&gt;. Dicha cabecera tiene varios campos que permiten especificar determinadas opciones que el cliente desea. Uno de esos campos es el campo &lt;em&gt;Accept &lt;/em&gt;que permite indicar que formatos de respuesta acepta el cliente y en que orden.&lt;/p&gt;  &lt;p&gt;P.ej. si hago una petición con Firefox a &lt;em&gt;http://www.google.es&lt;/em&gt;, el contenido del campo &lt;em&gt;Accept&lt;/em&gt; de la cabecera que firefox envia es (lo acabo de mirar con Firebug):&lt;/p&gt;  &lt;p&gt;&lt;code&gt;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;Que podríamos interpretar (más o menos) como: &lt;em&gt;Mis formatos preferidos son text/html y application/xhtml+xml, si no puedes en ninguno de esos dos, envíamelo en application/xml y si no puedes, pues me tragaré lo que me mandes.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;El valor exacto de dicha cabecera depende del browser… P.ej. IE8 para la misma peticion envia el siguiente valor en Accept (lo acabo de mirar con Fiddler):&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Courier New"&gt;image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Por lo tanto vemos como en el campo &lt;em&gt;Accept&lt;/em&gt; el cliente nos dice que formatos de respuesta entiende (y en que orden los prefiere).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2. Acceso a la cabecera desde ASP.NET MVC&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Imaginad que tenemos un controlador que puede devolver datos en dos formatos: XML y JSON. Y queremos usar el campo &lt;em&gt;Accept&lt;/em&gt; de la cabecera http que envíe el cliente para devolver los datos en uno u otro formato.&lt;/p&gt;  &lt;p&gt;Acceder a la cabecera http desde un controlador es extremadamente sencillo, usando &lt;strong&gt;Request.AcceptTypes&lt;/strong&gt;, que es un array con todos los campos de la cabecera a&lt;em&gt;ccept&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3. Devolver datos en formato XML&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;ASP.NET MVC no trae ningún mecanismo incluído para devolver datos en formato xml, lo que me va de coña para enseñaros como nos podemos crear un &lt;em&gt;ActionResult&lt;/em&gt; propio:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; XmlActionResult : ActionResult&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; _data;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XmlActionResult(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; data)&lt;br /&gt;    {&lt;br /&gt;        _data = data;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ExecuteResult(ControllerContext context)&lt;br /&gt;    {&lt;br /&gt;        XmlSerializer ser = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializer(_data.GetType());&lt;br /&gt;        context.HttpContext.Response.ContentType = &lt;span style="color: #006080"&gt;&amp;quot;text/xml&amp;quot;&lt;/span&gt;;&lt;br /&gt;        ser.Serialize(context.HttpContext.Response.OutputStream, _data);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Crear un ActionResult propio es trivial: deriváis de ActionResult y implementáis el método abstracto &lt;em&gt;ExecuteResult&lt;/em&gt; y en él hacéis lo que sea necesario (usualmente interaccionar con la Response). En este caso simplemente serializo el objeto que se le pasa con el serializador estándard de .NET. Ah si! Y pongo el content-type a &lt;em&gt;text/xml&lt;/em&gt; que es el content-type usado para documentos en XML.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Yo suelo acompañar los ActionResults propios con un método extensor para los controladores, para llamarlos de forma similar a los ActionResults que vienen en el framework. Mi método extensor (trivial) es:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ControllerExtensions&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; XmlActionResult Xml(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; ControllerBase @&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; data)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlActionResult(data);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y ahora ya puedo realizar la acción de mi controlador:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ActionResult List()&lt;br /&gt;{&lt;br /&gt;    var data = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; GeeksModel().GetAllGeeks();&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Request.AcceptTypes.Contains(&lt;span style="color: #006080"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;) ?&lt;br /&gt;        (ActionResult)Json(data, JsonRequestBehavior.AllowGet) :&lt;br /&gt;        (ActionResult)&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Xml(data);         &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simplemente pregunto si está el accept &lt;em&gt;application/json(*)&lt;/em&gt; &lt;a href="http://www.ietf.org/rfc/rfc4627.txt"&gt;(que parece ser el content-type para JSON)&lt;/a&gt;. Si lo está envío los datos en json y si no pues en xml! Si abrimos un navegador y vamos a /Geeks/List veremos los datos en XML porque ningún (bueno, ni FF ni IE que son los que he probado :p) envían &lt;em&gt;application/json&lt;/em&gt; en el &lt;em&gt;accept&lt;/em&gt; de la request.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;p&gt;(*) Ok, acepto que esta pregunta no es del todo correcta: debería mirar si application/json está preferido &lt;em&gt;antes que&lt;/em&gt; text/xml (por si me manda ambos). Igual que teoricamente, debería comprobar si no me manda ninguno de los dos, y si es el caso devolver un &lt;a href="http://www.checkupdown.com/status/E406_es.html"&gt;error 406&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;4. Un detallito final…&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Bueno, eso parece funcionar, pero lo que chirría un poco es tener que meter este if() para comprobar en &lt;em&gt;cada acción de cada controlador&lt;/em&gt; si la request contiene application/json o no y serializar el resultado en JSON o en XML.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para evitar esto he encontrado dos alternativas en la red:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Usar otro action result y que sea el action result quien decida si serializar los datos en XML o en JSON. Es decir, crearnos un JsonOrXmlActionResult, devolver siempre una instancia de este action result desde los controladores y en el &lt;em&gt;ExecuteResult&lt;/em&gt;, preguntar por el campo &lt;em&gt;accept&lt;/em&gt; y serializar en un formato en otro. Esta aproximación la he visto en el post “&lt;a href="http://omaralzabir.com/create_rest_api_using_asp_net_mvc_that_speaks_both_json_and_plain_xml/"&gt;Create REST API using ASP.NET MVC that speaks both Json and plain Xml&lt;/a&gt;” del blog de &lt;strong&gt;Omar Al Zabir&lt;/strong&gt;. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Otra aproximación totalmente distinta (pero muy interesante) que usa un &lt;em&gt;action filter&lt;/em&gt; para ello. Está en el blog de &lt;strong&gt;Aleem Bawany&lt;/strong&gt;, en el post “&lt;a href="http://aleembawany.com/2009/03/27/aspnet-mvc-create-easy-rest-api-with-json-and-xml/"&gt;ASP.NET MVC – Create easy REST API with JSON and XML&lt;/a&gt;”. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Os recomiendo la lectura de estos dos posts.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo y gracias a todos, especialmente a &lt;strong&gt;Hadi Hariri&lt;/strong&gt; quien con su comentario anterior, ha motivado este post! :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Como siempre, esto es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;! Pásate por allí mejor, que somos más!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-8790813792291907995?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/8790813792291907995/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=8790813792291907995' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8790813792291907995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/8790813792291907995'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/09/aspnet-mvc-formato-de-salida-segun.html' title='ASP.NET MVC – Formato de salida según Content-Type'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-2164470885330037245</id><published>2010-09-08T13:25:00.001+02:00</published><updated>2010-09-08T13:25:32.703+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net MVC'/><title type='text'>Subir ficheros al servidor en ASP.NET MVC</title><content type='html'>&lt;p&gt;Buenas! Hoy voy a responder alguna pregunta que me he encontrado en alguna vez, y es como &lt;em&gt;subir ficheros&lt;/em&gt; al servidor usando MVC2. &lt;/p&gt;  &lt;p&gt;La verdad es que con ASP.NET MVC2 subir ficheros al servidor &lt;strong&gt;es extremadamente simple&lt;/strong&gt;. Vamos a empezar viendo el código de una vista que permite subir un fichero al servidor, junto con una descripción adicional. La vista básicamente contiene un&amp;#160; &amp;lt;form&amp;gt; como el siguiente:&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt; &lt;span style="color: #ff0000"&gt;action&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;&amp;lt;%: Url.Action(&amp;quot;&lt;/span&gt;&lt;span style="color: #ff0000"&gt;Upload&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;quot;) %&amp;gt;&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;enctype&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;method&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;descripcion&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Descripción del fichero:&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;descripcion&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;descripcion&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;br&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt; &lt;span style="color: #ff0000"&gt;for&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;fichero&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Fichero:&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;label&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;file&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;fichero&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;size&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;br&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Enviar&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;form&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos que es HTML puro y duro, aunque el tag &amp;lt;form&amp;gt; lo podeis generar con Html.BeginForm() si queréis. La clave es añadir el atributo &lt;strong&gt;enctype&lt;/strong&gt; con el valor &lt;em&gt;multipart/form-data.&lt;/em&gt; Como se menciona en la &lt;a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2"&gt;especificación sobre formularios del W3C&lt;/a&gt;, el valor de multipart/form-data es el que debe usarse cuando se quieran enviar al servidor datos binarios.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El &amp;lt;input type=”file”&amp;gt; es el control HTML que nos permite seleccionar un fichero para enviar.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y desde el controlador? Pues sencillo, en este caso mi formulario tiene dos parámetros (&lt;em&gt;descripcion &lt;/em&gt;y &lt;em&gt;fichero&lt;/em&gt;), por lo que necesitaré que la acción del controlador tenga esos dos parámetros. El parámetro &lt;em&gt;descripcion&lt;/em&gt; es un string, pero el parámetro fichero… que és?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pues bien ASP.NET MVC es capaz de ver que el parámetro &lt;em&gt;fichero&lt;/em&gt; es un fichero que se ha subido al servidor y sabe &lt;em&gt;mapearlo&lt;/em&gt; a un objeto de la clase &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.httppostedfilebase.aspx"&gt;HttpPostedFileBase&lt;/a&gt;. Esta clase nos da acceso no sólo al contenido del fichero subido, sinó a más información (su content-type, su tamaño, el path completo desde donde se ha subido,…).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;El método del controlador queda pues, así de sencillo:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;[HttpPost]&lt;br /&gt;public ActionResult Upload(string descripcion, HttpPostedFileBase fichero)&lt;br /&gt;{&lt;br /&gt;    fichero.SaveAs(Path.Combine(@&amp;quot;d:\temp&amp;quot;, Path.GetFileName(fichero.FileName)));&lt;br /&gt;    return View();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fijaos en los dos parámetros string y HttpPostedFileBase. El método simplemente se guarda una copia del fichero subido en d:\temp, pero obviamente aquí podéis hacer lo que queráis.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Y listos! No hay que hacer nada más… qué, sencillo, no??? :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Un saludo&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD: Esta técnica &lt;strong&gt;no es ajax&lt;/strong&gt;, eso significa que mientras se está subiendo el fichero al servidor, la aplicación web no responde (el browser está haciendo la petición). Existe un mecanismo para realizar subidas de ficheros en background, aunque no es directo debido a que con XMLHttpRequest (el objeto del naveagador que hace posible ajax) no se pueden subir ficheros. Si estáis interesados en el siguiente &lt;a href="http://aspzone.com/tech/jquery-file-upload-in-asp-net-mvc-without-using-flash/"&gt;post de John Rudolf se muestra como realizar un upload de fichero en ajax usando jQuery y el form plugin&lt;/a&gt;! &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;PD2: Como no, eso es un crosspost desde &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;mi blog en geeks.ms&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/897874347676011387-2164470885330037245?l=burbujasnet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://burbujasnet.blogspot.com/feeds/2164470885330037245/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=897874347676011387&amp;postID=2164470885330037245' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2164470885330037245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/897874347676011387/posts/default/2164470885330037245'/><link rel='alternate' type='text/html' href='http://burbujasnet.blogspot.com/2010/09/subir-ficheros-al-servidor-en-aspnet.html' title='Subir ficheros al servidor en ASP.NET MVC'/><author><name>epna</name><uri>http://www.blogger.com/profile/02568454383791432108</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1JRa_Jfnm20/TTP1vXNnUSI/AAAAAAAAEIk/NIHcK0ghTiM/S220/demons%2540bay.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-897874347676011387.post-4357323305833324886</id><published>2010-08-25T13:39:00.001+02:00</published><updated>2010-08-25T13:39:51.625+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='framework'/><title type='text'>Opinión: bool es sólo para true/false</title><content type='html'>&lt;p&gt;Saludos a todos! Tanto a los que estéis trabajando, cómo aquellos que estando de vacaciones seais tan frikis que leais geeks.ms! :)&lt;/p&gt;  &lt;p&gt;Hoy quiero hablar un poco sobre &lt;em&gt;bool&lt;/em&gt;. Puede parecer un tipo de datos aburridote: a fin de cuentas sólo puede tener dos valores, pero precisamente ahí radica su gracia y de eso os quería contar. La idea del post es muy simple: &lt;em&gt;bool es sólo para true/false&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Por ejemplo, en los arcanos tiempos en que un servidor usaba Visual C++ 6 para el desarrollo de aplicaciones windows, en las MFCs había un método muy divertido llamado &lt;a href="http://msdn.microsoft.com/en-us/library/t9fb9hww(VS.80).aspx"&gt;UpdateData&lt;/a&gt; (que por lo que veo aún está). MFC tenía una cosa muy buena que era la posibilidad de realizar &lt;em&gt;bindings&lt;/em&gt; entre variables de la clase que representaba la ventana (usualmente una clase derivada de CWnd) y los controles que contenía dicha ventana. Eso, ahora, puede parecer una chorrada pero por aquel entonces era una auténtica pasada.&lt;/p
