<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Avanzis (Blogs Desarrollo)</title>
    <description>Avanzis (Blogs Desarrollo)</description>
    <link>http://www.avanzis.com/rssfeed/313/847.xml</link>
    <lastBuildDate>Tue, 25 Nov 2008 16:01:37 GMT</lastBuildDate>
    <item>
      <title>Utilizar Rhino Mocks y StructureMap en pruebas unitarias con NUnit</title>
      <description>En el posts anteriores ya vimos cómo &lt;strong&gt;utilizar y configurar StructureMap&lt;/strong&gt; para poner en práctica la inyección de dependencias.&lt;br /&gt;
&lt;br /&gt;
Tal y como prometí, ahora vamos a ver un pequeño ejemplo de cómo utilizar el StructureMap y el mocking de objetos en las pruebas unitarias.&lt;br /&gt;
&lt;br /&gt;
Quizá te preguntes que es un “&lt;strong&gt;Mock&lt;/strong&gt;”.&lt;br /&gt;
&lt;br /&gt;
Un mock, en el contexto de pruebas unitarias, es un objeto “falso” que simula el comportamiento del objeto real, con el fin de realizar las pruebas. En la &lt;a title="Definición de Mock" href="http://en.wikipedia.org/wiki/Mock_object"&gt;wikipedia &lt;/a&gt;lo asimilan al maniquí que utilizan los diseñadores coches para realizar las pruebas de accidentes. &lt;br /&gt;
&lt;br /&gt;
Te sugiero si utilizas pruebas unitarias, profundices más sobre este tema.&lt;br /&gt;
Existen muchas librerías para realizar mocks en .NET.&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;
    &lt;a title="Mock en .NET con Rhino Mocks" href="http://ayende.com/projects/rhino-mocks.aspx"&gt;&lt;strong&gt;Rhino Mocks&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;
    &lt;strong&gt;&lt;a href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;&lt;a href="http://www.nmock.org/"&gt;NMock&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
En el ejemplo que voy a plantear utilizaré &lt;strong&gt;&lt;a href="hhttp://ayende.com/projects/rhino-mocks.aspx"&gt;Rhino Mocks&lt;/a&gt;&lt;/strong&gt;, para crear un mock de un servicio de mensajería, ya que no quiero que realmente se envíe el correo electrónico al usuario, simplemente quiero probar que el método se llama convenientemente.&lt;br /&gt;
&lt;br /&gt;
Primero crearé la interfaz de este servicio de mensajería.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt;     &lt;span style="color: blue;"&gt;void&lt;/span&gt; SendMessage(&lt;span style="color: rgb(43, 145, 175);"&gt;User&lt;/span&gt; user, &lt;span style="color: blue;"&gt;string&lt;/span&gt; text);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; }&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
En la aplicación “real”, no en las pruebas unitarias, configuraré StructureMap para que el servicio de mensajería sea una implementación de esta interfaz para enviar correos electrónicos. Pero podría ser cualquier otra cosa, enviar SMS, un texto al Messenger, etc…&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; ConfigureStructureMap()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;ObjectFactory&lt;/span&gt;.Configure(s =&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt;         s.BuildInstancesOf&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt;&gt;()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt;         .TheDefaultIsConcreteType&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;EmailMessagingService&lt;/span&gt;&gt;());&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; }&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
El controlador de &lt;strong&gt;&lt;a href="http://www.asp.net/mvc/" target="_blank" title="ASP.NET MVC - Model View Controller"&gt;asp.net mvc&lt;/a&gt;&lt;/strong&gt; que queremos probar tiene la siguiente acción:&lt;br /&gt;
 &lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;ActionResult&lt;/span&gt; CreateUser(&lt;span style="color: blue;"&gt;string&lt;/span&gt; userName, &lt;span style="color: blue;"&gt;string&lt;/span&gt; password, &lt;span style="color: blue;"&gt;string&lt;/span&gt; email)&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;User&lt;/span&gt; user = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;User&lt;/span&gt;{UserName = userName, Password = password, Email = email};&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;UserValidationResult&lt;/span&gt; result = userService.Register(user);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt;     &lt;span style="color: blue;"&gt;if&lt;/span&gt; (result.IsValid)&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt;     {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt;         &lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt; messagingService = &lt;span style="color: rgb(43, 145, 175);"&gt;ObjectFactory&lt;/span&gt;.GetInstance&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt;&gt;();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt;         messagingService.SendMessage(user, &lt;span style="color: rgb(163, 21, 21);"&gt;"Tu cuenta ha sido creada correctamente"&lt;/span&gt;);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt;         &lt;span style="color: blue;"&gt;return&lt;/span&gt; Authenticate(userName, password, &lt;span style="color: blue;"&gt;null&lt;/span&gt;);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt;     }&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;     TempData[&lt;span style="color: rgb(163, 21, 21);"&gt;"RegisterErrors"&lt;/span&gt;] = result.Errors;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt;     &lt;span style="color: blue;"&gt;return&lt;/span&gt; RedirectToAction(&lt;span style="color: rgb(163, 21, 21);"&gt;"Register"&lt;/span&gt;);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt; }&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
Y ahora en las pruebas unitarias, comprobaremos que el método SendMessage se llama al crear un nuevo usuario. Utilizaremos &lt;strong&gt;&lt;a href="http://www.nunit.org"&gt;NUnit&lt;/a&gt;&lt;/strong&gt; como librería de pruebas y habrá que añadir la referencia al dll de Rhino Mocks de y de StructureMap al proyecto de pruebas.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; [&lt;span style="color: rgb(43, 145, 175);"&gt;Test&lt;/span&gt;]&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; CreateUser_Creates_Users_And_Sends_Email()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt; {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;MockRepository&lt;/span&gt; mocker = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;MockRepository&lt;/span&gt;();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt; messagingService = mocker.StrictMock&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;IMessagingService&lt;/span&gt;&gt;();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;Expect&lt;/span&gt;.Call(() =&gt; messagingService.SendMessage(&lt;span style="color: blue;"&gt;null&lt;/span&gt;, &lt;span style="color: blue;"&gt;null&lt;/span&gt;))&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt;         .IgnoreArguments();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt;     mocker.ReplayAll();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt;     &lt;span style="color: rgb(43, 145, 175);"&gt;ObjectFactory&lt;/span&gt;.Inject(messagingService);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt;     controller.CreateUser(&lt;span style="color: rgb(163, 21, 21);"&gt;"usuario"&lt;/span&gt;, &lt;span style="color: rgb(163, 21, 21);"&gt;"clave"&lt;/span&gt;, &lt;span style="color: rgb(163, 21, 21);"&gt;"direccion@correo.es"&lt;/span&gt;);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt;     mocker.VerifyAll();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt; }&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Veamos con más detalle el código de esta prueba.&lt;br /&gt;
&lt;br /&gt;
En la línea 1 le indico a &lt;a title="Librería de pruebas unitarias" target="_blank" href="http://www.nunit.org"&gt;&lt;strong&gt;NUnit&lt;/strong&gt;&lt;/a&gt; que este método es una prueba.&lt;br /&gt;
&lt;br /&gt;
En la línea 4 creamos el objeto de Rhino Mocks que se encargará de generar los objectos Mocks a partir de la definición de la interfaz.&lt;br /&gt;
&lt;br /&gt;
En la línea 6 creamos obtenemos la implementación simulada del servicio IMessagingService. &lt;br /&gt;
&lt;br /&gt;
En la líneas 8 y 9, le decimos a Rhino Mocks que esperamos que en el futuro se llame al método SendMessage del objeto messagingService y que nos dan igual los argumentos utilizados. El método Expect.Call espera como parámetro un delegado que se lo hemos pasado utilizando una expressión lambda. &lt;br /&gt;
&lt;br /&gt;
En la línea 12, le indicamos al objeto MockRepository que ya hemos fijado todas las expectativas (en nuestro caso, sólo la establecida en la línea 8) y que vamos a empezar las pruebas.&lt;br /&gt;
&lt;br /&gt;
En la línea 13, inyectamos la interfaz simulada a &lt;strong&gt;StructureMap &lt;/strong&gt;para que utilice este objeto, en vez de lo que tenga en su configuración.&lt;br /&gt;
&lt;br /&gt;
En la línea 14, llamamos al objeto que estamos probando con algunos parámetros por defecto.&lt;br /&gt;
&lt;br /&gt;
En la línea 15, le pedimos a &lt;strong&gt;Rhino Mocks&lt;/strong&gt;, que verifique que se han cumplido todas las expectativas establecidas. En nuestro caso queríamos que se llamara al método SendMessage al crear un usuario. Si esto no ocurriera, este método lanzaría una excepción por lo que la prueba unitaria no se pasaría correctamente.&lt;br /&gt;
&lt;br /&gt;
¡Espero que te haya servido de ayuda!&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/10414/837/utilizar-rhino-mocks-y-structuremap-en-pruebas-unitarias-con-nunit</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/10414/837/utilizar-rhino-mocks-y-structuremap-en-pruebas-unitarias-con-nunit</guid>
      <pubDate>Tue, 25 Nov 2008 16:01:37 GMT</pubDate>
    </item>
    <item>
      <title>Primeros pasos con StructureMap y la Inyección de Dependencias</title>
      <description>Uno de los objetivos que debe tener un buen programador es que su código esté poco acoplado, es decir, que dos componentes con funcionalidades distintas dependan el uno del otro lo mínimo posible. De esta forma conseguirá que sus dos componentes por separado sean reutilizables y más fáciles de mantener.&lt;br /&gt;
&lt;br /&gt;
Para eliminar al máximo la dependencia entre componentes, existe un patrón de diseño conocido como “&lt;strong&gt;Inyección de dependencias&lt;/strong&gt;” (“&lt;strong&gt;Dependency Injection&lt;/strong&gt;” o DI).  Este patrón consiste básicamente en que en vez de ser una clase la que crea objetos, estos se inyectan o resuelven en el último momento.&lt;br /&gt;
&lt;br /&gt;
Existen diferentes proyectos en .NET que intentan ayudarnos  a aplicar este patrón:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;&lt;a href="http://www.castleproject.org/container/index.html" target="_blank"&gt; Castle Windsor Container&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;
    &lt;strong&gt;&lt;a href="http://structuremap.sourceforge.net" target="_blank" title="Dependency Injection con StructureMap"&gt;StructureMap&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd203104.aspx" target="_blank" title="Unity Application Block"&gt; Microsoft Unity Application Block&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
He decidido comenzar a utilizar StructureMap porque que es uno de los más extendidos y además me gusta su sintaxis y facilidad de uso.&lt;br /&gt;
&lt;br /&gt;
Para comenzar a utilizar la inyección de dependencias debes acostumbrarte a utilizar interfaces en vez de objetos concretos ya que esto es lo que te permitirá diferentes implementaciones de esa interfaz.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo, si queremos un componentes que realice el registro de errores o eventos, crearemos una interfaz “ILogger”. Y además, dos implementaciones de esta interfaz, una para guardar los mensajes en una base de datos y otra en un archivo de texto.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    &lt;span style="color: blue;"&gt;void&lt;/span&gt; Log(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;
&lt;p style="margin: 0px;"&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;DatabaseLogger&lt;/span&gt; : &lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Log(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        &lt;span style="color: green;"&gt;// Lógica para guardar el mensaje en un archivo d texto..&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;
&lt;p style="margin: 0px;"&gt; &lt;/p&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;TextLogger&lt;/span&gt; :  &lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Log(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        &lt;span style="color: green;"&gt;// Lógica par aguardar el mensaje en un archivo de texto...&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
Muy bien, ya tenemos dado el primer paso. Ahora añadiremos la referencia en nuestro proyecto a StructureMap.dll para poder utilizar esta librería.&lt;br /&gt;
&lt;br /&gt;
Cuando queramos utilizar el objeto ILogger dentro de otra clase, llamaremos método GetInstance() del objeto ObjectFactory que ofrece StructureMap.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;ClaseDePrueba&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; HacerAlgo()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    {&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        &lt;span style="color: green;"&gt;// ...&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        &lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt; logger = &lt;span style="color: rgb(43, 145, 175);"&gt;ObjectFactory&lt;/span&gt;.GetInstance&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt;&gt;();&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        logger.Log(&lt;span style="color: rgb(163, 21, 21);"&gt;"Mensaje que queremos registrar"&lt;/span&gt;);&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        &lt;span style="color: green;"&gt;// ...&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
Pero te preguntarás, ¿cómo sabe StructureMap cuál de las dos implementaciones de ILogger debe devolver, la de la base de datos o la del  archivo de texto? Obviamente eso hay que indicárselo de alguna forma. &lt;br /&gt;
&lt;br /&gt;
Podemos &lt;strong&gt;configurar StructureMap&lt;/strong&gt; o bien utilizando el archivo de configuración App.config o Web.config si es una aplicación web. O mediante código, normalmente al iniciarse el programa o en el archivo Global.asax si trabajas con ASP.NET.&lt;br /&gt;
&lt;br /&gt;
En este ejemplo, le indicaremos por código a StructureMap que queremos utilizar el archivo de texto para guardar los logs.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 0%; font-family: courier new; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;
&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; ConfigureStructureMap()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(43, 145, 175);"&gt;ObjectFactory&lt;/span&gt;.Configure(&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;        s =&gt; s.BuildInstancesOf&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;ILogger&lt;/span&gt;&gt;()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;            .TheDefaultIsConcreteType&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;TextLogger&lt;/span&gt;&gt;()&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;    );&lt;/p&gt;
&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;
¡Eso es todo! Ya estamos utilizando StructureMap y a partir de ahora, con cambiar una simple línea de código (o una línea del archivo de configuración si hubiéramos utilizado esa opción) podemos comenzar a utilizar la base de datos para guardar los mensajes en toda la aplicación.&lt;br /&gt;
&lt;br /&gt;
La &lt;strong&gt;Inyección de dependencias&lt;/strong&gt; es un patrón de diseño que todo programador debería conocer y utilizar. Además, esta técnica, unida al “&lt;strong&gt;Mocking&lt;/strong&gt;”, te será realmente útil si utilizas (¡deberías hacerlo!) &lt;strong&gt;pruebas unitarias&lt;/strong&gt;. Pero de esto ya hablaré en el futuro.&lt;br /&gt;
&lt;br /&gt;
¡Espero vuestros comentarios!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/10401/837/primeros-pasos-con-structuremap-y-la-inyeccion-de-dependencias</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/10401/837/primeros-pasos-con-structuremap-y-la-inyeccion-de-dependencias</guid>
      <pubDate>Tue, 25 Nov 2008 13:26:48 GMT</pubDate>
    </item>
    <item>
      <title>El SEO y sus puntos clave.</title>
      <description>El SEO, o Search Engine Optimization, se refiere al conjunto de técnicas que debemos aplicar en una Web para que esté optimizada en buscadores y que salgamos bien posicionados.$0$0Técnicas SEO hay muchísimas, pero en mi opinión hay 6 que destacan sobre todas las demás:$0$0$0Tener &lt;span&gt;&lt;a href="http://www.sitemaps.org/"&gt;sitemaps&lt;/a&gt;&lt;/span&gt;.$0$0La palabra/frase clave debe ser el título de la página.$0$0La palabra/frase clave debe encontrarse dentro de la url de la página.$0$0La palabra/frase clave (debe estar dentro de un)/(debe ser el) H1 en la página.$0$0La palabra/frase clave debe estar repetida varias veces dentro de la página, algunas de ellas con negrita.$0$0Estructura de enlaces internos: todas las páginas de tu Web deben estar enlazadas entre ellas con pocos saltos de diferencia.$0$0Todo ello bajo la premisa de tener un buen contenido. Sin buen contenido no empezamos ni a hablar. Será este buen contenido el que te proporcione enlaces entrantes, y será la constancia el que haga que Google confíe en ti.$0$0Si estás interesado en técnicas SEO más avanzadas, te recomiendo el blog &lt;span&gt;&lt;a title="comunactivo" href="http://comunactivo.subgurim.net/"&gt;comunactivo&lt;/a&gt;&lt;/span&gt;.</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/10190/831/el-seo-y-sus-puntos-clave</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/10190/831/el-seo-y-sus-puntos-clave</guid>
      <pubDate>Wed, 19 Nov 2008 13:38:35 GMT</pubDate>
    </item>
    <item>
      <title>Jugando con jQuery: emulando el FindControl de ASP.NET</title>
      <description>Esto de &lt;strong&gt;jQuery&lt;/strong&gt; es divertido. Igual de divertido que &lt;strong&gt;javascript &lt;/strong&gt;pero más fácil.&lt;br /&gt;
&lt;br /&gt;
Hace unos días di una primero &lt;strong&gt;&lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/9120/831/introduccion-a-jquery"&gt;introducción a jQuery&lt;/a&gt;&lt;/strong&gt; e hice mi &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/9123/831/jugando-con-jquery-macemulator"&gt;primer plugin&lt;/a&gt; que llamé macEmulator.&lt;br /&gt;
&lt;br /&gt;
Ahora presento un nuevo plugin que responde a una necesidad real y casi diaria de todo programador en ASP.NET (a no ser que trabaje con &lt;a href="http://www.avanzis.com/blogs/richard-chamorro/i/8677/837/asp-net-mvc-preview-5"&gt;MVC&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Se trata de emular el FindControl de ASP.NET pero con javascript. Vayamos a un ejemplo:&lt;br /&gt;
&lt;br /&gt;
Tenemos un DataList con un ItemTemplate que tiene dos Panels y un Label en cada Panel&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;asp:DataList ID="DataList1" runat="server"&gt;&lt;br /&gt;
    &lt;ItemTemplate&gt;&lt;br /&gt;
        &lt;asp:Panel ID="Panel1" runat="server"&gt;&lt;br /&gt;
            &lt;asp:Label ID="Label1" runat="server" Text="Label1"&gt;&lt;/asp:Label&gt;&lt;br /&gt;
        &lt;/asp:Panel&gt;&lt;br /&gt;
        &lt;asp:Panel ID="Panel2" runat="server"&gt;&lt;br /&gt;
            &lt;asp:Label ID="Label2" runat="server" Text="Label2"&gt;&lt;/asp:Label&gt;&lt;br /&gt;
        &lt;/asp:Panel&gt;&lt;br /&gt;
    &lt;/ItemTemplate&gt;&lt;br /&gt;
&lt;/asp:DataList&gt;&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Esto generará un código HTML que convertirá las Label en elementos &lt;span /&gt; con un identificador de este estilo: &lt;em&gt;DataList1_ctl00_Label1&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Pero yo lo que quiero es acceder a las Label1 por jQuery... ¿cómo lo hago?&lt;br /&gt;
&lt;br /&gt;
No hay una forma directa porque los IDs los genera ASP.NET, pero con el plugin que presento podremos hacer algo como esto:&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;var controls = $(document).findControl('Label1');&lt;br /&gt;
for (i = 0; i &lt; controls.length; i++) { alert(controls[i].innerHTML); }&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
El plugin no es que sea una obra de arte. Más bien es sencillito, jeje. Lo autoexplican los comentarios:&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;jQuery.fn.findControl = function(clientId) {&lt;br /&gt;
    var ids = new Array();&lt;br /&gt;
    &lt;br /&gt;
    // Para cada elemento que tenga un atributo ID dentro de "this"&lt;br /&gt;
    $(this).find('*[id]').each(function(i) {&lt;br /&gt;
        // Si el ID del elemento termina como el clientId, lo añadimos al array&lt;br /&gt;
        if (this.id &amp;&amp;&lt;br /&gt;
            (this.id.lastIndexOf(clientId) &gt;= 0) &amp;&amp; &lt;br /&gt;
            (this.id.lastIndexOf(clientId) == (this.id.length - clientId.length))) {&lt;br /&gt;
                ids.push(this);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
    // Devolvemos el array&lt;br /&gt;
    return ids;&lt;br /&gt;
}&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
El plugin ya viene con bugs por defecto, como el hecho de que si otro elemento se llamara MyLabel1, el plugin se creería que es Label1... pero bueno, es una primera aproximación.&lt;br /&gt;
&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/9162/831/jugando-con-jquery-emulando-el-findcontrol-de-asp-net</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/9162/831/jugando-con-jquery-emulando-el-findcontrol-de-asp-net</guid>
      <pubDate>Sun, 05 Oct 2008 10:54:49 GMT</pubDate>
    </item>
    <item>
      <title>Jugando con jQuery: macEmulator</title>
      <description>Tras la breve &lt;strong&gt;&lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/9120/831/introduccion-a-jquery"&gt;introducción a jQuery&lt;/a&gt;&lt;/strong&gt;, propongo un ejemplo que he llamado "macEmulator". La verdad es que soy bastante malo dando nombre a las cosas, y en el mundo de la programación tenemos que estar todo el santo día dando nombres a variables, a funciones, a clases, a ficheros...&lt;br /&gt;
&lt;br /&gt;
El "macEmulator" lo que hace es coger las imágenes ubicadas dentro del "div" que le indiquemos y darles un efecto similar al de los iconos de los Mac. Cuando el ratón está encima de un icono la imagen se hace grande (progresivamente) y cuando sales se hace pequeña (también de forma progresiva).&lt;br /&gt;
&lt;br /&gt;
Lo he puesto dentro de un plugin, de forma que activar la funcionalidad se reduce a una sola línea de código:&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;strong&gt;$("#divId").macEmulation(100,150,100,500);&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Donde:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;divId es el "id" del div en el que están ubicadas las imágenes.&lt;/li&gt;
    &lt;li&gt;El primer parámetro marca la anchura inicial de las imágenes&lt;/li&gt;
    &lt;li&gt;El segundo parámetro marca la anchura de la imagen cuando el ratón está sobre ella.&lt;/li&gt;
    &lt;li&gt;El tercer parámetro marca la anchura de la imagen cuando el ratón deja de estar sobre ella.&lt;/li&gt;
    &lt;li&gt;El cuarto parámetro marca el tiempo que tarda la imagen en transformarse progresivamente de grande a pequeña y de pequeña a grande.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
A continuación muestro el código con comentarios para entender el script:&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;jQuery.fn.macEmulation = function(initialWitdh, hoverWidth, houtWidth, delay) {&lt;br /&gt;
    // Cogemos el elemento dentro del cual estarán las imágenes&lt;br /&gt;
    var div = $(this);&lt;br /&gt;
&lt;br /&gt;
    // Cuando la página esté cargada, aplicaremos la anchura inicial marcada&lt;br /&gt;
    // y pondremos cada imagen dentro de un div con unos estilos predefinidos&lt;br /&gt;
    $(document).ready(function() {&lt;br /&gt;
        div.find('img').width(initialWitdh);&lt;br /&gt;
        div.find('img').wrap('&lt;div style="float:left; padding-right:5px;"&gt;&lt;/div&gt;');&lt;br /&gt;
&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // Asignamos la anchura de la imagen cuando estamos sobre ella y cuando dejamos de estarlo.&lt;br /&gt;
    // Para ello utilizaremos el modo "animate" que hará que la transición sea progresiva.&lt;br /&gt;
    div.find('img').hover(&lt;br /&gt;
    function() {&lt;br /&gt;
        $(this).animate({ width: hoverWidth + "px" }, delay);&lt;br /&gt;
    },&lt;br /&gt;
    function() {&lt;br /&gt;
        $(this).animate({ width: houtWidth + "px" }, delay);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/em&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/9123/831/jugando-con-jquery-macemulator</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/9123/831/jugando-con-jquery-macemulator</guid>
      <pubDate>Thu, 02 Oct 2008 13:46:17 GMT</pubDate>
    </item>
    <item>
      <title>Introducción a jQuery</title>
      <description>&lt;strong&gt;Javascript &lt;/strong&gt;ha sido siempre un eterno candidato a desaparecer. Sin embargo, con el paso de los años su importancia en el mundo Web ha ido en aumento.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Javascript &lt;/strong&gt;no suele gustar. Se puede hacer muchísimas cosas con él, pero tiene varios inconvenientes. Empezando por la selectiva incompatibilidad entre navegadores, y acabando por una curva de aprendizaje no lineal (hacer cosas fáciles es fácil, hacer cosas difíciles es muy difícil... y en el medio hay poquito).&lt;br /&gt;
&lt;br /&gt;
Para los que hemos trabajado con javascript desde sus inicios, solemos tener pequeñas librerías que nos hacen todo lo que queremos. Pero suelen ser librerías poco estándar... vamos, que cada uno las tiene de su padre y de su madre.&lt;br /&gt;
&lt;br /&gt;
Es por eso que últimamente en la oficina suena mucho "&lt;strong&gt;&lt;a href="http://www.avanzis.com/blogs/richard-chamorro/i/9010/837/jquery-en-visual-studio-algo-esta-cambiando-en-microsoft"&gt;jQuery&lt;/a&gt;&lt;/strong&gt;", del que &lt;a href="http://www.avanzis.com/blogs/richard-chamorro"&gt;Richard&lt;/a&gt; ya ha hablado. Básicamente, &lt;strong&gt;jQuery&lt;/strong&gt; es un framework javascript, que nos permite olvidarnos de las incompatibilidades y linealiza mucho la curva de aprendizaje. El framework propone un estándar de trabajo con &lt;strong&gt;javascript&lt;/strong&gt;, que no sólo lo hace más fácil sino que le añade funcionalidades extremadamente útiles en pocas líneas de código.&lt;br /&gt;
&lt;br /&gt;
Para más regocijo, su &lt;a href="http://jquery.com/"&gt;Web oficial&lt;/a&gt; es muy útil, clara y llena de ejemplos, con buenos &lt;a href="http://docs.jquery.com/Tutorials"&gt;tutoriales&lt;/a&gt; y &lt;a href="http://plugins.jquery.com/"&gt;muchos plugins&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
En próximos artículos pondré ejemplos de algunas de las cosas que se puede hacer con jQuery. Serán ejemplo específicos, porque la &lt;a href="http://jquery.com/"&gt;Web oficial de jQuery&lt;/a&gt; ya es muy clara.&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/9120/831/introduccion-a-jquery</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/9120/831/introduccion-a-jquery</guid>
      <pubDate>Thu, 02 Oct 2008 13:30:44 GMT</pubDate>
    </item>
    <item>
      <title>ASP.NET MVC Preview 5</title>
      <description>!Acaban de lanzar la&lt;a title="ASP.NET MVC Preview 5" href="http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx"&gt; preview 5 de ASP.NET MVC&lt;/a&gt; en Codeplex!&lt;br /&gt;
&lt;br /&gt;
Si eres de los valientes (como nosotros) que estas desarrollando con ASP.NET MVC, recuerda que tendrás que desinstalar la versión anterior antes de instalar este nuevo lanzamiento.&lt;br /&gt;
&lt;br /&gt;
Por si nos os apetece leer, y ya que tengo que revisar los cambios en profundidad, aquí tenéis  algunas de las nuevas características respecto a la Preview 4:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Mejoras en los motores de visualización (ViewEngine)&lt;/strong&gt;&lt;br /&gt;
    &lt;ul&gt;
        &lt;li&gt;Ahora, en vez de ser cada controlador el responsable de decidir que motor de visualización se utilizará, los motores se registran de forma global.&lt;/li&gt;
        &lt;li&gt;Se ha modificado la interfaz IViewEngine para que añada el método "RenderPartial".&lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Mejoras en los helpers&lt;/strong&gt;
    &lt;ul&gt;
        &lt;li&gt;Soporte para la renderización de views parciales.&lt;/li&gt;
        &lt;li&gt;Nuevo parámetro para poder indicar a un DropDownList cuál será su opción por defecto.&lt;/li&gt;
        &lt;li&gt;Se han movido las extensiones AJAX a otro namespace, teóricamente para que sea más sencillo reemplazarlas por tu propio código.&lt;/li&gt;
        &lt;li&gt;Otras mejoras&lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Mejoras en los controles y los filtros.&lt;/strong&gt;
    &lt;ul&gt;
        &lt;li&gt;Los parámetros de las acciones ahora soportan también arrays. &lt;br /&gt;
        Esto ocurría cuando varios controles tienen el mismo nombre.&lt;/li&gt;
        &lt;li&gt;Soporte a para crear tus propios "binders". Los binders asocian los valores que llegan por querystring o form con parámetros de la acción.&lt;/li&gt;
        &lt;li&gt;Añadida la interfaz "IActionInvoker" para desacoplar el controlador la implementación específica de "ControllerActionInvoker".&lt;/li&gt;
        &lt;li&gt;Añadido el modo actualización (UpdateMode) a la clase del controlador. Es posible utilizar este método para actualizar las propiedades de un modelo a partir de los parámetros pasados en el formulario.&lt;/li&gt;
        &lt;li&gt;Se ha modificado "HandleErrorAttribute" para que mientras estás desarrollando aparezca la ventana amarilla de error que proporciona la máxima información posible.&lt;/li&gt;
        &lt;li&gt;Nuevo atributo "AcceptVerbs". Permite indicar qué verbos HTTP son aceptados (GET, POST, etc...). Esto permite tener dos acciones con el mismo nombre siempre y cuando acepten verbos diferentes.&lt;/li&gt;
        &lt;li&gt;Nuevo atributo "ActionName". Permite indicar un nombre de acción a un método diferente del nombre del método. Su ejemplo para estas dos últimas mejoras es bastante claro:&lt;br /&gt;
        &lt;br /&gt;
        [AcceptVerb("GET")]&lt;br /&gt;
        public ActionResult MyAction(...);&lt;br /&gt;
        &lt;br /&gt;
        [ActionName("MyAction"), AcceptVerb("POST")]&lt;br /&gt;
        public ActionResult MyAction_FormSubmit(...);&lt;br /&gt;
        &lt;br /&gt;
        [AcceptVerb("GET")]&lt;br /&gt;
        public ActionResult OtherActionOverloaded(string id);&lt;br /&gt;
        &lt;br /&gt;
        [AcceptVerb("POST")]&lt;br /&gt;
        public ActionResult OtherActionOverloaded(string id, ...);&lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Muy bonita toda esta explicación, pero ¿cómo nos ha afectado a nostros en &lt;a title="Proyecto ASP.NET MVC" href="http://www.avanzis.com/blogs/josep-planells/i/8292/834/scrum-test-driven-development-y-mvc-vamos-a-ser-agiles"&gt;el proyecto que estamos realizando en ASP.NET MVC&lt;/a&gt;?&lt;br /&gt;
&lt;br /&gt;
Estos son los problemas que hemos encontrado para que nuestro proyecto compile tras haber actualizado a la preview 5:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;El objeto "LinkBuilder" ahora se encuentra en el espacio de nombre "Microsoft.Web.Mvc". Este objeto lo utilizamos para generar un "RouteValueDictionary" a partir de una expresión de Linq. &lt;/li&gt;
    &lt;li&gt;El método ActionLink&lt;T&gt; que adminte como tipo un controlador, se ha movido también a Microsoft.Web.Mvc.&lt;/li&gt;
    &lt;li&gt;BindingHelperExtensions ya no existe y aún no he encontrado ningún objeto equivalente.&lt;/li&gt;
    &lt;li&gt;El controlador ya no tiene la propiedad ViewEngine.ç&lt;/li&gt;
    &lt;li&gt;Html.RenderUserControl() ya no existe, ahora hay que usar Html.RenderPartial(). Por ejemplo:&lt;br /&gt;
     &lt;%=Html.RenderUserControl("~/UserControls/TagList.ascx", ViewData.Model.PopularTags)%&gt;&lt;br /&gt;
    Ahora será:&lt;br /&gt;
     &lt;% Html.RenderPartial("~/UserControls/TagList.ascx", ViewData.Model.PopularTags);%&gt;&lt;br /&gt;
    Fíjate que ahora no hay que poner el igual delante, y que tiene que acabar con punto y coma. &lt;/li&gt;
&lt;/ul&gt;
¿Alguien más se está peleando con ASP.NET MVC? Me encantaría escuchar vuestros comentarios.  &lt;br /&gt;
&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/8677/837/asp-net-mvc-preview-5</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/8677/837/asp-net-mvc-preview-5</guid>
      <pubDate>Thu, 28 Aug 2008 17:14:20 GMT</pubDate>
    </item>
    <item>
      <title>Scrum, Test Driven Development y MVC. Vamos a ser ágiles.</title>
      <description>En Avanzis estamos empezando un proyecto que nos ilusiona mucho, y que esperamos que vea la luz antes de final de año. Como todo proyecto que empieza, uno de los primeros aspectos a decidir es qué metodología vamos a seguir y qué plataforma tecnológica. En este proyecto vamos a utilizar &lt;a href="http://es.wikipedia.org/wiki/Scrum"&gt;Scrum&lt;/a&gt; y &lt;a href="http://es.wikipedia.org/wiki/Tdd"&gt;Test Driven Development&lt;/a&gt;. Vale. Y ahora os preguntareis ¿esto qué significa?. Pues básicamente son dos relativamente nuevas metodologías en el desarrollo de software, clasificadas dentro de las llamadas “ágiles”. Estas dos metodologías tienen algo en común. Se asume que el diseño de la arquitectura de clases, la definición de las funcionalidades y la especificación de requisitos, es un proceso que fluye a través de todo el desarrollo del proyecto, y no son una etapa inicial aislada. No hay que esperar a tener el diseño y la especificación completa para empezar a desarrollar. Scrum es una manera de organizarse, y TDD es una manera de desarrollar.     &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;¿Qué es SCRUM?&lt;/strong&gt; &lt;br /&gt;
&lt;br /&gt;
Scrum es una metodología de trabajo ágil, especialmente diseñada para intentar acortar los ciclos de desarrollo y conseguir una mejor aproximación entre las funcionalidades del software y los requerimientos del cliente. Se trata de evitar la burocracia innecesaria,  conseguir una mayor versatilidad frente a los cambios y empezar rápidamente a trabajar, de manera que el cliente puede ir viendo lo antes posible los avances en el proyecto. Es óptima para equipos de trabajo no demasiado grandes y clientes que tengan un alto grado de implicación en el proyecto. El procedimiento básico consiste en crear un repositorio con las funcionalidades requeridas para el proyecto, asignándoles unos puntos de importancia, una estimación en horas y cómo se debe demostrar esta funcionalidad. A esto lo llamaremos “Product Backlog”. A partir de entonces, se crean los “Sprint Backlogs”, que son un conjunto de tareas que se deben completar en un determinado tiempo, entre 2 semanas y un mes. Durante cada dia del sprint, se hace una corta reunión para revisar el estado de las tareas, y al final de cada sprint, una reunión con el cliente para mostrarle los resultados. Así, el cliente va viendo los avances cada corto periodo de tiempo, y se puede reajustar cualquier cambio de funcionalidad en cualquier etapa del proyecto. Obtenemos un feedback que nos permite mejorar en el siguiente sprint. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;¿Qué es TDD?&lt;/strong&gt;&lt;br /&gt;
 &lt;br /&gt;
Para tratar de mejorar del código, existen los  “&lt;a href="http://en.wikipedia.org/wiki/Unit_testing"&gt;Unit Tests&lt;/a&gt;”, que consisten en código adicional que se ocupa de probar el código principal. Se trata de probar que pequeñas unidades individuales de código se comportan tal y como esperamos. Para ello existen frameworks como &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt; con el fin de ayudarnos en esta tarea. Mediante los test, tenemos una mayor seguridad en que las cosas funcionan como deben, y además, podemos comprobar que las cosas siguen funcionando bien después de hacer cambios en el código. Pero TDD va más allá. En lugar de programar y luego probar, se intercambia el orden, de manera que primero creamos los test, y a partir de aquí se va creando la funcionalidad. El ciclo que se va repitiendo es: Añadir el test para una nueva funcionalidad. Evidentemente, este test fallará dado que la funcionalidad no está implementada. Programaremos, ejecutaremos todos los tests hasta que todos ellos tengan éxito, y finalmente refactorizaremos y volveremos a empezar. En el modelo habitual, se dedica una parte muy importante del tiempo diseñando completamente los modelos lógicos y físicos antes de escribir ninguna línea de código. Sin embargo, con este modelo, el diseño se deriva de los test de funcionalidad, y es un proceso que discurre al mismo tiempo que el propio desarrollo. Por esto, está metodología de desarrollo encaja perfectamente en la metodología organizativa SCRUM. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;MVC&lt;/strong&gt; &lt;br /&gt;
&lt;br /&gt;
Finalmente, teníamos que elegir una plataforma tecnológica para desarrollar el proyecto siguiendo esta metodología. Para ello, hemos elegido seguir el patrón &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;Model View Controller&lt;/a&gt; , y en concreto la implementación de &lt;a href="http://www.asp.net/mvc/"&gt;asp.net MVC&lt;/a&gt;. Las metodologías anteriores se pueden utilizar con cualquier plataforma, pero MVC proporciona un modelo ideal para realizar los test de una manera mucho más completa, probando no solo la lógica sino también la interacción con la interfaz de usuario. Pero sobre MVC, ya hablaremos en detalle en próximos posts. &lt;br /&gt;
&lt;br /&gt;
Así que ya sabéis, durante un tiempo, hablaremos de nuestras experiencias con SCRUM, TDD y MVC.
</description>
      <link>http://www.avanzis.com/blogs/josep-planells/i/8292/834/scrum-test-driven-development-y-mvc-vamos-a-ser-agiles</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/josep-planells/i/8292/834/scrum-test-driven-development-y-mvc-vamos-a-ser-agiles</guid>
      <pubDate>Thu, 24 Jul 2008 00:42:49 GMT</pubDate>
    </item>
    <item>
      <title>Lucene para ASP.NET (Parte III). Búsqueda. </title>
      <description>Siguiendo la serie de artículos sobre &lt;strong&gt;Lucene &lt;/strong&gt;(&lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7596/831/lucene-para-asp-net-parte-i-introduccion"&gt;Lucene para ASP.NET (Parte I). Introducción&lt;/a&gt; y &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7803/831/lucene-para-asp-net-parte-ii-indexacion"&gt;Lucene para ASP.NET (Parte II). Indexación&lt;/a&gt;), dónde conocimos qué era Lucene y cómo &lt;strong&gt;indexar contenidos&lt;/strong&gt;, durante este artículo vamos a hablar de la búsqueda, sin duda, el objetivo último que perseguimos.&lt;br /&gt;
&lt;br /&gt;
Según la estructura del &lt;strong&gt;Document &lt;/strong&gt;planteada en el artículo sobre &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7803/831/lucene-para-asp-net-parte-ii-indexacion"&gt;Indexación&lt;/a&gt;, cuando queramos buscar algo atacaremos a los campos "Title" y "Text", pues son los que contendrán la información importante. Es decir, lo que queremos es "buscar palabras que se encuentran en el título o en el texto".&lt;br /&gt;
&lt;br /&gt;
A continuación tenemos un método que busca en ambos campos y devuelve un listado de Document's:&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;public static List&lt;Document&gt; SearchDocuments(string sQuery)&lt;br /&gt;
{&lt;br /&gt;
    // Creamos el listado documents que vamos a devolver&lt;br /&gt;
    List&lt;Document&gt; documents = new List&lt;Document&gt;();&lt;br /&gt;
    &lt;br /&gt;
    // Abrimos el IndexSearcher con el Path del directorio que  hace de índice. Aquí usamos una variable global.&lt;br /&gt;
    IndexSearcher searcher = new IndexSearcher(IndexPath);&lt;br /&gt;
&lt;br /&gt;
    try&lt;br /&gt;
    {&lt;br /&gt;
        // Buscamos en Text&lt;br /&gt;
        QueryParser qpText = new QueryParser("Text", new SpanishAnalyzer());&lt;br /&gt;
        Query queryText = qpText.Parse(sQuery);&lt;br /&gt;
&lt;br /&gt;
        // Buscamos en Title&lt;br /&gt;
        QueryParser qpTitle = new QueryParser("Title", new SpanishAnalyzer());&lt;br /&gt;
        Query queryTitle = qpTitle.Parse(sQuery);&lt;br /&gt;
&lt;br /&gt;
        // Unimos ambos elementos: queremos que nuestro query se encuentre en uno de los dos sitios. &lt;br /&gt;
        // Si puede ser en los dos, mejor.&lt;br /&gt;
        BooleanQuery bq = new BooleanQuery();&lt;br /&gt;
        bq.Add(queryText, BooleanClause.Occur.SHOULD);&lt;br /&gt;
        bq.Add(queryTitle, BooleanClause.Occur.SHOULD);&lt;br /&gt;
&lt;br /&gt;
        // La clase Hits es la clave. Es lo que nos devolverá la Search&lt;br /&gt;
        Hits hits = searcher.Search(bq);&lt;br /&gt;
        int totalHits = hits.Length();&lt;br /&gt;
&lt;br /&gt;
        // Recorremos todos los Hits, recogemos el document y lo añadimos a nuestro listado genérico&lt;br /&gt;
        // Aquí es donde debería hacerse la paginación, etc.&lt;br /&gt;
        for (int i = 0; i &lt; totalHits; i++)&lt;br /&gt;
        {&lt;br /&gt;
            Document document = hits.Doc(i);&lt;br /&gt;
            documents.Add(document);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    finally&lt;br /&gt;
    {&lt;br /&gt;
        searcher.Close();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return documents;&lt;br /&gt;
}&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
Como vemos, el código se autoexplica bastante.&lt;br /&gt;
&lt;br /&gt;
Lo más importante es saber que &lt;em&gt;QueryParser &lt;/em&gt;define dónde queremos buscar y con qué Analyzer, y &lt;em&gt;Query &lt;/em&gt;define qué queremos buscar.&lt;br /&gt;
&lt;br /&gt;
Con el BooleanQuery uniremos las búsquedas en ambos campos, indicándole mediante el SHOULD que los resultados deben encontrarse en al menos uno de los dos campos (Title o Text), pero que si puede ser en los dos, mejor que mejor.&lt;br /&gt;
&lt;br /&gt;
Los resultados tras el searcher.Search(...) vienen en forma de Hits. Los Hits contienen el Document, pero también contienen otros campos interesantes como el Score que devuelve la puntuación de 0 a 100 o el Length que devuelve el número de resultados encontrados.&lt;br /&gt;
&lt;br /&gt;
Como véis esto ha sido una búsqueda a pelo. Ahora quedaría paginar, filtrar los resultados con Score bajo, etc.&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/8245/831/lucene-para-asp-net-parte-iii-busqueda</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/8245/831/lucene-para-asp-net-parte-iii-busqueda</guid>
      <pubDate>Tue, 22 Jul 2008 10:36:29 GMT</pubDate>
    </item>
    <item>
      <title>Cómo obtener únicamente la fecha de un campo DateTime de SQL Server</title>
      <description>Estaba realizando una consulta en &lt;strong&gt;T-SQL&lt;/strong&gt; para mostrar el número de pedidos realizados por día entre dos fechas. Algo relativamente simple, ¿verdad?&lt;br /&gt;
&lt;br /&gt;
Pues aunque parezca increíble, &lt;strong&gt;SQL Server&lt;/strong&gt; no proporciona una función sencilla que permita &lt;strong&gt;obtener únicamente la fecha de un campo de tipo DateTime&lt;/strong&gt; ignorando la hora almacenada. En el caso del informe que quería realizar, me impedía agrupar correctamente los pedidos por fecha porque el campo &lt;strong&gt;DateTime&lt;/strong&gt; también almacena la hora.&lt;br /&gt;
&lt;br /&gt;
Afortunadamente, &lt;a href="http://blogs.x2line.com/al/archive/2006/02/17/1458.aspx" title="Anatoly Lubarsky"&gt;Anatoly Lubarsky&lt;/a&gt; nos proporciona una solución bastante sencilla.&lt;br /&gt;
&lt;pre&gt;SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, CAMPO_FECHA))&lt;/pre&gt;
Donde CAMPO_FECHA es el nombre del campo de la tabla que contiene la fecha que quieres procesar. También puedes utilizar GETDATE() en vez de CAMPO_FECHA para obtener únicamente la fecha de hoy.&lt;br /&gt;
&lt;br /&gt;
Esta es la consulta SQL resultante:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, DateCreated)) as OrderDate, &lt;br /&gt;COUNT(*) as OrdersCount FROM CommerceOrders&lt;br /&gt;GROUP BY DATEADD(dd, 0, DATEDIFF(dd, 0, DateCreated))&lt;br /&gt;ORDER BY OrderDate&lt;/pre&gt;
Vuestros comentarios son bienvenidos.&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/8156/837/como-obtener-unicamente-la-fecha-de-un-campo-datetime-de-sql-server</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/8156/837/como-obtener-unicamente-la-fecha-de-un-campo-datetime-de-sql-server</guid>
      <pubDate>Tue, 15 Jul 2008 13:50:25 GMT</pubDate>
    </item>
    <item>
      <title>Mejora el rendimiento de Firefox al visitar páginas de tu ordenador</title>
      <description>!Firefox me encanta! &lt;br /&gt;
&lt;br /&gt;
Firefox es mi navegador favorito para navegar por Internet por su velocidad y simplicidad, pero sobre todo gracias a extensiones como &lt;a href="http://getfirebug.com/" target="_parent" title="Firebug - el mejor complemento de Firefox para diseñadores web"&gt;&lt;strong&gt;Firebug &lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt;que son imprescindibles para cualquier desarrollador web. &lt;br /&gt;
&lt;br /&gt;
Me gustaría utilizar este navegador para realizar las pruebas de las aplicaciones en ASP.NET, pero por algún motivo Firefox se muestra extremadamente lento cuando se conecta a las páginas del ordenador local (localhost). ¡Pero esta mañana he leído &lt;a href="http://scottonwriting.net/sowblog/posts/13367.aspx" title="Solución del problema de rendimiento con firefox al conectar a un servidor local"&gt;la solución a ese problema&lt;/a&gt;!&lt;br /&gt;
&lt;br /&gt;
Básicamente, consiste en entrar en la configuración avanzada de Firefox, introduciendo about:config en la URL del navegador, y cambiar el parámetro 'network.dns.ipv4OnlyDomains' a 'localhost'. &lt;br /&gt;
&lt;br /&gt;
Pruébalo, y notarás la diferencia.&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/7890/837/mejora-el-rendimiento-de-firefox-al-visitar-paginas-de-tu-ordenador</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/7890/837/mejora-el-rendimiento-de-firefox-al-visitar-paginas-de-tu-ordenador</guid>
      <pubDate>Wed, 09 Jul 2008 13:42:34 GMT</pubDate>
    </item>
    <item>
      <title>Lucene para ASP.NET (Parte II). Indexación. </title>
      <description>Tras hablar de &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7569/831/un-buscador-avanzado-para-tu-web"&gt;buscadores avanzados&lt;/a&gt; para Webs e &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7596/831/lucene-para-asp-net-parte-i-introduccion"&gt;introducir Lucene para ASP.NET&lt;/a&gt;, a lo largo de este artículo hablaremos de cómo hacer la &lt;strong&gt;indexación con Lucene&lt;/strong&gt;.&lt;br /&gt;
&lt;br /&gt;
Distinguimos tres pasos básicos cuando hacemos la indexación:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;Abrir el índice.&lt;/li&gt;
    &lt;li&gt;Crear y añadir el Document (del que ya hablamos en el &lt;a href="httphttp://www.avanzis.com/blogs/xavi-navarro/i/7596/831/lucene-para-asp-net-parte-i-introduccion" title="ASP.NET Lucene"&gt;anterior artículo&lt;/a&gt;).&lt;/li&gt;
    &lt;li&gt;Optimizar el índice.&lt;/li&gt;
&lt;/ol&gt;
&lt;strong&gt;&lt;br /&gt;
&lt;span style="font-size: 12px;"&gt;
Abrir el índice&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
Lo primero un ejemplo de cómo se abre un &lt;strong&gt;índice&lt;/strong&gt;:
&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;IndexWriter writer = new IndexWriter(IndexPath, new SpanishAnalyzer(), !Directory.Exists(IndexPath)); 
&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
El constructor de "IndexWriter" consta de tres parámetros:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;em&gt;IndexPath&lt;/em&gt;: donde indicaremos el Path del directorio que hemos creado como índice. Este directorio es muy importante. Evitaremos tocar nada de lo que veamos ahí dentro ;)&lt;/li&gt;
    &lt;li&gt;&lt;em&gt;Analyzer&lt;/em&gt;: una de las características de Lucene es que tiene en cuenta las características del lenguaje a la hora de indexar (así como de buscar). Por ejemplo, el SpanishAnalyzer indica que hay palabras con poca importancia (como las preposiciones), que no tenga demasiado en cuenta los acentos, etc.&lt;/li&gt;
    &lt;li&gt;&lt;em&gt;Crear índice&lt;/em&gt;: por tonto que parezca (a mí me lo parece) hay que indicarle si quieres crear o no el índice... ya podría hacer la comprobación solito, pero bueno, sobreviviremos indicando que si existe el directorio es que existe el índice.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;span style="font-size: 12px;"&gt;&lt;strong&gt;Crear y añadir el Document&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
Sin duda la fase más importante. Ya sabemos que el &lt;strong&gt;Document&lt;/strong&gt;, en una analogía con una base de datos relacional, sería algo así como la estructura de una tabla.&lt;br /&gt;
&lt;br /&gt;
Debemos definir muy bien qué queremos indexar y cómo. Tenemos diferentes opciones de indexación para cada campo del Document:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;Guardar el valor y no separar las palabras.&lt;/li&gt;
    &lt;li&gt;Guardar el valor, no separar las palabras y no indexar.&lt;/li&gt;
    &lt;li&gt;No guardar el valor y no separar las palabras.&lt;/li&gt;
    &lt;li&gt;Separar las palabras y no guarda. &lt;/li&gt;
&lt;/ul&gt;
Tener que indicar la opción de "Guardar" puede resultar difícil de entender para los que trabajamos con bases de datos relacionales. Hay que tener en cuenta que Lucene está pensada a lo grande, y todo lo que sea optimizar es poco.&lt;br /&gt;
&lt;br /&gt;
Siempre que podamos debemos indexar y no guardar, sobretodo en lo referente a textos. Por ejemplo, si quisiéramos hacer un buscador para "El Quijote" nos interesaría indexarlo, pero no guardar todo su contenido, dado que no es lo que le vamos a mostrar en los resultados de buscador al usuario. Una técnica habitual cuando se quieren indexar textos largos es crear un campo de "Indexar y no guardar" para el texto completo, y otro de "Guardar y no indexar" para un resumen de ese texto largo.&lt;br /&gt;
&lt;br /&gt;
El concepto de "Separar palabras" también es digno de mención. cuando lo indicamos (usando Field.Index.TOKENIZED) le estamos diciendo a Lucene que aplique los filtros del Analyzer. Sin embargo hay ocasiones en que queremos mantener la información tal cual, sin filtros, para lo que indicaremos Field.Index.UN_TOKENIZED.&lt;br /&gt;
&lt;br /&gt;
Vayamos al grano y creemos el Document de ejemplo:
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;Document document = new Document();
&lt;br /&gt;
&lt;br /&gt;
// Guardar el valor y no separar las palabras&lt;br /&gt;
document.Add(new Field("Identificador", ID, Field.Store.YES, Field.Index.UN_TOKENIZED));&lt;br /&gt;
document.Add(new Field("Fecha", MyDate, Field.Store.YES, Field.Index.UN_TOKENIZED)); &lt;br /&gt;
&lt;br /&gt;
// Guardar el valor, no separar las palabras y no indexar&lt;br /&gt;
document.Add(new Field("ResumenDelTexto", Summary, Field.Store.YES, Field.Index.NO)); &lt;br /&gt;
&lt;br /&gt;
// Separar la palabras y guardar&lt;br /&gt;
document.Add(new Field("Title", Title, Field.Store.YES, Field.Index.TOKENIZED));         &lt;br /&gt;
&lt;br /&gt;
// Separar las palabras y no guardar &lt;br /&gt;
document.Add(new Field("Texto", Text, Field.Store.NO, Field.Index.TOKENIZED)); &lt;br /&gt;
&lt;br /&gt;
writer.AddDocument(document);&lt;/em&gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vemos que el modo de trabajar es muy intuitivo. Como Document entendemos a "La estructura" y como Field entendemos "El campo" con sus características.&lt;br /&gt;
&lt;br /&gt;
Llegados aquí, vuelvo a repetir que lo más importante a la hora de hacer un buscador es saber indexarlo bien. Conocidas las opciones posibles para crear un Field del Document, hay que pararse a pensar en qué y cómo queremos indexar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 12px;"&gt;&lt;strong&gt;Optimizar el índice&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
Lucene provee de la opción de &lt;strong&gt;optimizar el índice&lt;/strong&gt;. Como siempre sucede en estos casos, el proceso de optimizar es muy pesado, pero tiene como consecuencia que las búsquedas serán más rápidas. &lt;br /&gt;
&lt;br /&gt;
De modo que tenemos que encontrar un equilibrio entre el coste computacional de indexar y el coste computacional de buscar. Tendremos desde Webs que no indexen apenas nada y se pasen el día haciendo búsquedas, o la Web que indexa mucho pero que hace pocas búsquedas.&lt;br /&gt;
&lt;br /&gt;
Y como en el centro está la virtud, para &lt;a href="http://www.todoexpertos.com"&gt;Todoexpertos&lt;/a&gt; he optado la siguiente opción "artesanal":&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;
if ((DateTime.Now.Millisecond % 500) == 0) writer.Optimize();
&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 12px;"&gt;&lt;strong&gt;Estructura final&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
Juntando un poquito las piezas, he aquí la estructura básica de la indexación con Lucene que utilizamos en Todoexpertos:&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
public static void Index(QuestionInfo questionInfo)&lt;br /&gt;
{&lt;br /&gt;
    IndexWriter writer = null;&lt;br /&gt;
    lock (LuceneIndexing)&lt;br /&gt;
    {&lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            // Abrimos el índice&lt;br /&gt;
            writer = new IndexWriter(IndexPath, new SpanishAnalyzer(), !Directory.Exists(IndexPath));&lt;br /&gt;
&lt;br /&gt;
            // Accede a un método que crea el Document... aquí es donde hay que pensar :D&lt;br /&gt;
            Document document = GetDocument(questionInfo);&lt;br /&gt;
&lt;br /&gt;
            writer.AddDocument(document);&lt;br /&gt;
&lt;br /&gt;
            if ((DateTime.Now.Millisecond % 500) == 0)&lt;br /&gt;
                writer.Optimize();&lt;br /&gt;
        }&lt;br /&gt;
        finally&lt;br /&gt;
        {&lt;br /&gt;
            // Poniéndolo en el finally nos aseguramos que el writer queda cerrado. Muy importante: SIEMPRE debe quedar cerrado.&lt;br /&gt;
            if (writer != null)&lt;br /&gt;
                writer.Close();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En el próximo artículo veremos cómo podemos &lt;strong&gt;buscar con Lucene&lt;/strong&gt;.&lt;br /&gt;
&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/7803/831/lucene-para-asp-net-parte-ii-indexacion</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/7803/831/lucene-para-asp-net-parte-ii-indexacion</guid>
      <pubDate>Thu, 03 Jul 2008 14:55:44 GMT</pubDate>
    </item>
    <item>
      <title>Cómo ignorar los acentos en las búsquedas con SQL Server</title>
      <description>&lt;p style="margin: 0cm 0cm 10pt"&gt;Una de los requisitos más habituales para un buscador es que al realizar las búsquedas no distinga las palabras que se diferencian sólo por acentos. Por ejemplo, si buscas la palabra “como”, también se desea que les aparezcan los resultados con las palabra “cómo”.&lt;/p&gt;
&lt;p style="margin: 0cm 0cm 10pt"&gt;Hacer esto es SQL Server es muy sencillo, si sabes cómo. &lt;/p&gt;
&lt;p style="margin: 0cm 0cm 10pt"&gt;El truco está en cambiar la &lt;b&gt;intercalación&lt;/b&gt; (“Collation” en inglés) del campo en el que quieres buscar o bien de la base de datos completa, para que utilice alguna de las intercalaciones que ignoran los acentos, que son aquellas acabadas en “_IA” (Insensitive Accent).&lt;/p&gt;
&lt;p style="margin: 0cm 0cm 10pt"&gt;La sentencia para cambiar una base de datos completa para utilizar la intercalación “Modern_Spanish_CI_AI”:&lt;/p&gt;
&lt;pre&gt;ALTER DATABASE [nombrebasededatos] COLLATE Modern_Spanish_CI_AI&lt;/pre&gt;
&lt;p style="margin: 0cm 0cm 10pt"&gt;Si lo que queremos es sólo cambiar un campo de una tabla, el administrador de SQL Server te hace la vida más fácil. Sólo tienes que editar las propiedades de la columna, y quitar la opción de “Distinguir acentos” en el formulario que aparece al intentar modificar la propiedad “Intercalación”.&lt;/p&gt;
&lt;p style="margin: 0cm 0cm 10pt"&gt;Espero que os haya sido de utilidad.&lt;/p&gt;
</description>
      <link>http://www.avanzis.com/blogs/richard-chamorro/i/7796/837/como-ignorar-los-acentos-en-las-busquedas-con-sql-server</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/richard-chamorro/i/7796/837/como-ignorar-los-acentos-en-las-busquedas-con-sql-server</guid>
      <pubDate>Thu, 03 Jul 2008 10:45:08 GMT</pubDate>
    </item>
    <item>
      <title>Elección del CRM</title>
      <description>En &lt;a href="http://www.avanzis.com"&gt;Avanzis&lt;/a&gt; hemos utilizado varios &lt;a href="http://es.wikipedia.org/wiki/CRM"&gt;CRM&lt;/a&gt; hasta la fecha. Empezamos utilizando el &lt;a href="http://www.superoffice.com"&gt;SuperOffice&lt;/a&gt;, pero nos resultaba demasiado complejo para realizar algunas tareas simples. Después de intentar sin demasiado éxito la implantación del producto de Microsoft, realizamos un desarrollo simple para uso interno, si bien se queda muy corto para las necesidades actuales.&lt;br /&gt;
&lt;br /&gt;
Así que nos hemos puesto manos a la obra, para realizar una investigación de las alternativas existentes. Una de las primeras alternativas ha sido el &lt;a href="http://www.sugarcrm.com"&gt;SugarCRM&lt;/a&gt;. Sin embargo, su modelo de licencias no nos ha convencido. Después de analizar otros como &lt;a href="http://www.splendidcrm.com/"&gt;Splendid CRM&lt;/a&gt;, &lt;a href="http://www.compiere.com/"&gt;Compiere&lt;/a&gt;, &lt;a href="http://otrs.org/"&gt;OTRS&lt;/a&gt;, &lt;a href="http://www.hipergate.org/"&gt;Hipergate&lt;/a&gt; o &lt;a href="http://sinergia.sourceforge.net/"&gt;Sinergia&lt;/a&gt;, nos hemos decidido a implementar el CRM &lt;a href="http://www.vtiger.com/"&gt;vtiger&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Nos han convencido varias cosas. Entre ellas, la facilidad para realizar las tareas más comunes, como la gestión de cuentas, contactos, actividades, pedidos, etc.., o la disponibilidad de un "customer portal" donde los clientes puedan introducir sus incidencias o "tickets", todo ello con localización disponible para castellano. También dispone de un plug-in para Outlook para poder realizar desde el programa de la suite de Office algunas de las tareas más comunes. Además, es gratuito y open source. Está desarrollado en PHP sobre MySql. En nuestro caso, lo vamos a utilizar en la primera fase como organizador de contactos y cuentas, y como gestor de incidencias primordialmente, de manera complementaria con la aplicación de gestión de bugs, &lt;a href="http://www.bugnetproject.com/"&gt;BugNET&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
¿Qué os parece nuestra elección? ¿Usáis algún CRM con el que estéis especialmente contentos?&lt;br /&gt;
</description>
      <link>http://www.avanzis.com/blogs/josep-planells/i/7639/834/eleccion-del-crm</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/josep-planells/i/7639/834/eleccion-del-crm</guid>
      <pubDate>Wed, 18 Jun 2008 17:21:27 GMT</pubDate>
    </item>
    <item>
      <title>Lucene para ASP.NET (Parte I). Introducción.</title>
      <description>Tras hablar de la necesidad de un &lt;a href="http://www.avanzis.com/blogs/xavi-navarro/i/7569/831/un-buscador-avanzado-para-tu-web"&gt;buscador avanzado para Web&lt;/a&gt;, comentamos que en Todoexpertos.com usamos &lt;a href="http://incubator.apache.org/lucene.net/"&gt;Lucene para ASP.NET&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
En este artículo vamos a introducir qué es exactamente Lucene y los puntos maestros de cómo funciona. Lo primero de todo, obviamente, es &lt;a href="https://svn.apache.org/repos/asf/incubator/lucene.net/site/download/"&gt;descargarse el .sln de Lucene&lt;/a&gt;, para poder trabajar con él.&lt;br /&gt;
&lt;br /&gt;
En general, cualquier motor de búsqueda tiene dos elementos clave: la &lt;strong&gt;indexación &lt;/strong&gt;y la &lt;strong&gt;búsqueda&lt;/strong&gt;. Primero hay que definir sobre qué se quiere buscar y cómo, y luego ya buscaremos. Ya anticipo que la parte de indexación es mucho más compleja que la de búsqueda, y es en la que más tiempo nos pasaremos pensando.&lt;br /&gt;
&lt;br /&gt;
Lo bueno de &lt;strong&gt;Lucene&lt;/strong&gt;, es que tanto la indexación como la búsqueda giran entorno a lo mismo: el &lt;strong&gt;Document&lt;/strong&gt;, que es sin duda uno de los elementos más importante. Entendiendo qué es el Document ya tenemos muchísimo ganado.&lt;br /&gt;
&lt;br /&gt;
Además, acostumbrados como estamos a lo que es una &lt;strong&gt;Base de Datos&lt;/strong&gt;, usaremos paralelismos, con la premisa de que sólo sirven para hacernos a una idea:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;La "&lt;strong&gt;tabla&lt;/strong&gt;" de la base de datos tiene su analogía en Lucene con el "&lt;strong&gt;index&lt;/strong&gt;". Un "index" acaba siendo un directorio con varios archivos determinados, de los cuales no queremos saber nada. Sólo nos interesa saber su nombre y que todo el directorio debe tener permisos de lectura y escritura.&lt;/li&gt;
    &lt;li&gt;La "&lt;strong&gt;estructura de la tabla&lt;/strong&gt;" de la base de datos es el "&lt;strong&gt;Document&lt;/strong&gt;". El Document no se define de forma fija desde un principio. Lo vamos a generar en código, "al vuelo".&lt;/li&gt;
    &lt;li&gt;Los "&lt;strong&gt;campos de la tabla&lt;/strong&gt;" son los "&lt;strong&gt;Fields&lt;/strong&gt;" del Document. Igual que en una base de datos definiríamos el tipo de datos del "Field" o si es Nullable o no, los Fields de Lucene requieren una serie de definiciones que veremos en artículos posteriores.&lt;/li&gt;
&lt;/ul&gt;
Expresándolo en pseudocódigo:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;Indexación&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
&lt;em&gt;Función Indexar(parámetros)&lt;br /&gt;
{&lt;br /&gt;
&lt;/em&gt;
&lt;blockquote&gt;&lt;em&gt;Indice = AbrirIndice();&lt;br /&gt;
&lt;br /&gt;
Document doc = new Document();&lt;br /&gt;
doc.AñadirField(new Field(parametros1));&lt;br /&gt;
doc.AñadirField(new Field(parametros2));&lt;br /&gt;
&lt;br /&gt;
Indice.AñadirDocument(doc);&lt;br /&gt;
&lt;br /&gt;
Indice.Cerrar();&lt;br /&gt;
&lt;/em&gt;
&lt;/blockquote&gt;&lt;em&gt;}&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;Búsqueda&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
&lt;em&gt;Función Buscar(parámetros)&lt;br /&gt;
{&lt;br /&gt;
&lt;/em&gt;
&lt;blockquote&gt;&lt;em&gt;Indice = AbrirIndice();&lt;br /&gt;
&lt;br /&gt;
DocumentCollection docs = Indice.Buscar(parámetros);&lt;br /&gt;
&lt;br /&gt;
Indice.Cerrar(); &lt;/em&gt;
&lt;/blockquote&gt;&lt;em&gt;}&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
En próximos artículos veremos exactamente cómo se hace la indexación y como la búsqueda.&lt;br /&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
</description>
      <link>http://www.avanzis.com/blogs/xavi-navarro/i/7596/831/lucene-para-asp-net-parte-i-introduccion</link>
      <guid isPermaLink="true">http://www.avanzis.com/blogs/xavi-navarro/i/7596/831/lucene-para-asp-net-parte-i-introduccion</guid>
      <pubDate>Sun, 15 Jun 2008 10:51:18 GMT</pubDate>
    </item>
  </channel>
</rss>