<?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-35785998</id><updated>2012-02-16T09:54:50.989+01:00</updated><category term='NUnit'/><category term='XSLT'/><category term='MVC'/><category term='Test Driven Development'/><category term='SPOIL'/><category term='Javascript'/><category term='Visual Studio 2005'/><category term='SQL Server 2005'/><category term='Design'/><category term='XML'/><category term='Report'/><category term='Generics'/><category term='Reporting Services'/><category term='SPS 2007'/><category term='ASP.NET'/><category term='Testing'/><category term='XQuery'/><category term='TDD'/><category term='OOP'/><category term='Queries'/><category term='Seguridad'/><category term='Debug'/><category term='Patterns'/><category term='Errores Comunes'/><category term='.NET'/><title type='text'>ASP.NET MadGas</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-35785998.post-6385090595066721155</id><published>2008-01-17T18:18:00.000+01:00</published><updated>2008-01-17T18:38:27.522+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD 4 everyone</title><content type='html'>Desconocido para muchos (para mí hasta hace año y medio), de los pocos que lo conocen, son menos los que lo usan (ni hablo de los que lo usan bien...). No obstante, hay gente que apuesta por TDD y aporta su granito de arena con aplicaciones que lo faciliten y con documentación que realmente merece la pena.&lt;br /&gt;&lt;br /&gt;Aquí quiero hacer un breve compendio de recursos, aplicaciones y de blogs que nos acercan TDD, para que nos demos cuenta de que TDD no es exclusivo de una tecnología, es una forma de trabajar:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;TDD para Javascript en ASP.NET:&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Herramienta: &lt;a href="http://www.valleyhighlands.com/testingframeworks/"&gt;JSNUnit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Walkthrough: &lt;a href="http://www.testdrivenjavascript.com/Practice/5.aspx"&gt;A simple TDD Example&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;TDD para Java:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Herramienta: &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Artículos: &lt;a href="http://www.junit.org/taxonomy/term/12"&gt;JUnit Articles&lt;/a&gt;, &lt;a href="http://www.javaworld.com/javaworld/jw-12-2004/jw-1206-tdd.html?page=3"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Libro: &lt;a href="http://www.amazon.com/gp/product/0131482394?ie=UTF8&amp;amp;tag=wwwpacificdat-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0131482394%22%3EAgile%20Java%28TM%29:%20Crafting%20Code%20with%20Test-Driven%20Development%20%28Robert%20C.%20Martin%20Series%29%3C/a%3E%3Cimg%20src=%22http://www.assoc-amazon.com/e/ir?t=wwwpacificdat-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0131482394%22%20width=%221%22%20height=%221%22%20border=%220%22%20alt=%22%22%20style=%22border:none%20%21important;%20margin:0px%20%21important;%22%20/%3E"&gt;Agile Java, by Jeff Langr&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Nota: alguien más habituado que yo a trabajar con Java podrá rellenar esta lista, porque en este campo estoy bastante limitado&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;TDD para .NET&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Herramienta: &lt;a href="http://www.nunit.org/index.php"&gt;NUnit&lt;/a&gt;, &lt;a href="http://msdn2.microsoft.com/es-es/teamsystem/default.aspx"&gt;Visual Studio Team System 2005&lt;/a&gt;, &lt;a href="http://msdn2.microsoft.com/es-es/vstudio/default.aspx"&gt;Visual Studio 2008&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Libros: &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0735619484/ref=pd_ecc_rvi_3/104-4781899-3884732"&gt;Test Driven Development in Microsoft .NET by Newkirk &amp;amp; Vorontsov&lt;/a&gt;,&lt;br /&gt;&lt;a href="http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1200591153&amp;amp;sr=1-1"&gt;Test Driven Development: By Example by Kent Beck &lt;/a&gt;&lt;/li&gt;&lt;li&gt;Artículos: &lt;a href="http://www.developerfusion.co.uk/show/5240/"&gt;Test Driven Development Using NUnit in C#, Test-Driven Development in .NET - Introduction &amp;amp; Unit Tests&lt;/a&gt;, &lt;a id="viewpost.ascx_TitleUrl" href="http://www.agileprogrammer.com/oneagilecoder/archive/2005/11/28/9859.aspx"&gt;Real Test Driven Development with Visual Studio Team System&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Hay mucha más información, para ello tenéis que ir a una de las mejores fuentes de información sobre TDD... &lt;a href="http://www.google.es/"&gt;Google&lt;/a&gt;.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Un saludo @Madrid&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-6385090595066721155?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/6385090595066721155/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=6385090595066721155' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/6385090595066721155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/6385090595066721155'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/tdd-4-everyone.html' title='TDD 4 everyone'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-5288817140163029515</id><published>2008-01-17T15:11:00.000+01:00</published><updated>2008-01-17T15:18:05.038+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>¿TDD de propiedades?</title><content type='html'>Las propiedades tienen cierta lógica, de validación por ejemplo. Por ello, no sonaría descabellado que se lanzaran tests contra esas propiedades, pero ¿es realmente necesario?&lt;br /&gt;&lt;br /&gt;En este caso es imposible decir un "Sí" o un "No" rotundo. Depende de la cantidad de lógica que tengamos en la propiedad en cuestión, puede ser o no necesario. Muchas veces usamos las propiedades cuando realmente un campo nos proporciona la misma funcionalidad, o cuando usamos clases que requieren inicialización, para inicializarlas y que no nos devuelvan &lt;em&gt;NullException&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Cómo pone en este mensaje de un &lt;a href="http://tech.groups.yahoo.com/group/testdrivendevelopment/message/27392"&gt;foro de Yahoo Groups &lt;/a&gt;da una guía bastante buena para esta duda y otras muchas:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="font-size:85%;"&gt;Here's a rule of thumb for you: don't test anything when the complexity of the test approaches or surpasses the complexity of the code being tested (unless defect-free code is imperative, in whichcase you should expect to pay a high price to achieve it). In the caseof getters and setters, you're as likely to make an error in the test as you are in the code being tested (assuming you manually construct setters and getters; if not, then there can be no mistakes).&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;En resumen, no hagas tests de algo si los tests que lo prueban son igual de complicados o más que lo que está probando. Igual que puedes cometer un error en la aplicación, puedes cometerlo en el test.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Un saludo @Madrid&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-5288817140163029515?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/5288817140163029515/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=5288817140163029515' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5288817140163029515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5288817140163029515'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/tdd-de-propiedades.html' title='¿TDD de propiedades?'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-5413171057545999226</id><published>2008-01-17T12:27:00.000+01:00</published><updated>2008-01-17T15:05:48.483+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>¿Por qué usamos y por qué no usamos TDD?</title><content type='html'>Bueno chicos, volvemos al TDD, que ya llevaba mucho tiempo desde el último artículo en este sentido. La discusión que quiero plantear hoy es ¿Por qué usamos TDD? y ¿Por qué no usamos TDD?&lt;br /&gt;&lt;br /&gt;La verdad es que TDD no es una de las técnicas más utilizadas dentro de las metodologías. He tenido la suerte de conocerla y utilizarla en casos reales, que es donde se ve qué es lo que aporta y que es lo que no.&lt;br /&gt;&lt;br /&gt;Varias veces hemos visto el famoso gráfico de los costes de los cambios según la fase en la que está el proceso. Evidentemente, un cambio en la fase de requisitos afecta bastante menos que un cambio cuando la aplicación está a punto de entregarse. Para refrescar la mente, dad un vistacillo a esta &lt;a href="http://www.developerfusion.co.uk/show/6875/"&gt;página&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Partiendo de que estamos de acuerdo con ese gráfico y, asumiendo que siempre ha habido, hay y habrá cambios no planeados en nuestra aplciación (cambios en los requerimientos, errores en el diseño que obligan a tocar módulos, mejora y optimización del rendimiento...), tenemos que encontrar una forma de poder absorver esos cambios con el mínimo impacto.&lt;br /&gt;&lt;br /&gt;La solución es el desarrollo iterativo. Antes de aplicarlo, leed este &lt;a href="http://www-128.ibm.com/developerworks/rational/library/1742.html"&gt;artículo &lt;/a&gt;para poder aplicarlo lo mejor posible. La base de este modelo, es ir desarrollando la funcionalidad de mi aplicación poco a poco. Simplificando mucho este proceso, podríamos tener el siguiente caso con la tan manida calculadora.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Hablamos con el cliente y nos dice que quiere una calculadora. Pero no quiere una calculadora normal y corriente, quiere una adaptada a su negocio. Iniciamos la captura de requisitos.&lt;/li&gt;&lt;li&gt;Conforme llegan los primeros requisitos (que sume y que reste), el equipo de desarrollo comienza a implementar esas dos funcionalidades.&lt;/li&gt;&lt;li&gt;Para cuando nos llegan otros dos requisitos (multiplicar y dividir) nuestra aplicación ya tiene el código necesario para sumar y restar, y estamos probándolos.&lt;/li&gt;&lt;li&gt;El equipo de desarrollo ha acabado de probar los dos primeros requerimientos y empieza a desarrollar los otros dos. Mismo procedimiento: implementacion + pruebas + correccion de errores.&lt;/li&gt;&lt;li&gt;Entre medias, el usuario quiere ver una demo de lo que vamos haciendo hasta ahora. Como nos movemos por funcionalidades concretas, podemos enseñarle la parte de sumar y restar. En caso de que hubieramos hecho todo en bloque, no tendríamos nada acabado, y no podríamos enseñar nada.&lt;/li&gt;&lt;li&gt;Una vez vista la demo, nos dicen que no se deberían poder meter negativos en la suma, pero sí en la resta. El equipo de desarrollo adapta esa parte de la aplicación. La resta no se toca y siguen trabajando con la multiplicación y la división.&lt;/li&gt;&lt;li&gt;Pasa el tiempo y, tras repetirse los puntos 1-6 varias veces, se entrega la aplicación a los usuarios para un UAT (test de aceptación del usuario). Concluyen que falta funcionalidad, que no se acordaron de decirnos porque lo daban por supuesto... No pasa nada, volvemos al punto 1, sabiendo que el resto de la aplicación no debería tener excesivo impacto.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Esto no es siempre tan fácil y tan teórico. Surgen prisas y nos saltamos puntos. O juntamos puntos. Además, el trabajo en equipo tiene particularidades que hacen que algunos pasos sean más complicados que otros.&lt;/p&gt;&lt;p&gt;Este desarrollo por ciclos se coplementa muy bien con TDD. Tests que prueban la funcionalidad (tanto que se cumplen los requisitos, como que los resultados son los correctos). Esos tests siempre están y me pueden decir qué es lo que debo hacer. Como dice &lt;a href="http://dannorth.net/introducing-bdd"&gt;Dan North &lt;/a&gt;en su blog:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;I had introduced a bug. Bad me. Solution: Fix the bug.&lt;br /&gt;The intended behaviour was still relevant but had moved elsewhere. Solution: Move the test and maybe change it.&lt;br /&gt;The behaviour was no longer correct – the premise of the system had changed. Solution: Delete the test.&lt;/strong&gt;&lt;/em&gt; &lt;/p&gt;&lt;p&gt;Son un punto de partida. Nueva funcionalidad necesitará nuevos tests, pero los que estén no cambiarán. Cambios en la funcionalidad necesitarán cambios en los tests e, incluso, algunos nuevos. Errores en la lógica de la aplicación necesitarán cambios en los tests o más tests o tests más precisos.&lt;/p&gt;&lt;p&gt;Nunca tengais miedo de cambiar un test si veis que no prueba lo que debe de probar.&lt;/p&gt;&lt;p&gt;Tras esta introducción, vamos a analizar las preguntas del principio:&lt;/p&gt;&lt;p&gt;¿Por qué no usamos TDD?&lt;/p&gt;&lt;p&gt;Empezamos con la negativa. Las causas más comunes son:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;No sabemos que existe, o, si lo sabemos, no sabemos cómo se aplica. Efectivamente, nadie nace sabido, pero existe una cantidad brutal de libros y de documentación sobre Agile, TDD, BDD, Testing... &lt;/li&gt;&lt;li&gt;Es dificil montar un equipo que sepa usar TDD, y sin miedo. Algún día debe ser el primero. Por esa regla de tres, nadie habría empezado a usar OOP o los Web Services. Ante todo, que la gente que debe enseñarlo, se haya documentado muy bien y tenga una mínima experiencia.&lt;/li&gt;&lt;li&gt;Tardamos más en desarrollar la aplicación. Esto es verdad, pero los que lo dicen como excusa deben decir también que el desarrollo es sólo una de las fases de un proyecto, que generalmente no llega a la mitad del tiempo del proyecto. Se alarga la fase de desarrollo, pero a cambio, se acortan la otras. Para ser más precisos, no es que se acorten, sino que se solapan.&lt;/li&gt;&lt;li&gt;Mantener Tests + Codigo es más costoso que Mantener Código. Falso. En una aplicación donde un cambio afecta a 6 proyectos y 40 clases, es mucho más sencillo cambiar el código y ejecutar automáticamente los 300 tests que haya, para ver si afecta en algún otro punto, que ponerte a probar la aplicación exhaustivamente punto por punto y opción por opción.&lt;/li&gt;&lt;li&gt;Tener tests, añade labor de documentación. Sí, totalmente de acuerdo, pero eso era bueno, ¿no? Más documentación, más informción, mejor mantenibilidad.&lt;/li&gt;&lt;li&gt;Desconocimiento de herramientas. Visual Studio Team System 2005 integra el desarrollo y los tests, y permite automatizarlos. Visual Studio 2008 también trae los proyectos de test y, para los más humildes, siempre podéis usar &lt;a href="http://www.nunit.org/index.php"&gt;NUnit &lt;/a&gt;junto con una Express Edition.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Y ahora, ¿Por qué usamos TDD? Muchas de las respuestas se han dado en los 6 puntos anteriores, pero podemos añadir más.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Es una garantía de funcionamiento. Con unos tests bien diseñados, el hecho de pasar todos los tests, implica que nuestro código cumple los requisitos.&lt;/li&gt;&lt;li&gt;Implica mayor conocimiento de la aplicación. Diseñar e implementar un test requiere saber exactamente qué es lo que debe de ejecutar nuestra lógica. Es decir, nos permite ver una caja negra que debe de cumplir los test, que va a hacer que nos centremos en QUÉ hace (funcionalidad) y no en COMO lo hace (código).&lt;/li&gt;&lt;li&gt;No es exclusivo de un lenguaje. No es sólo de C#, ni VB.NET. Ni siquiera es exclusibo a .NET. Se puede usar en Java. Alguien que sabe TDD en un lenguaje lo sabe en todos.&lt;/li&gt;&lt;li&gt;Mezcla gestión de proyecto con desarrollo. Permite que los desarrolladores tengan una visión más global de la aplicación, porque deben saber los requisitos para poder desarrollar los tests.&lt;/li&gt;&lt;li&gt;Permite un análisis de efectividad. Cuanta más información tengamos de la evolución de un proyecto, mejor podremos detectar errores y subsanarlos, bien durante el desarrollo del proyecto, bien en el post-mortem. Los tests aportan información de cuanto código está testeado, cuanto funciona y cuanto no, cuanto influye un cierto cambio...&lt;/li&gt;&lt;li&gt;Da una garantía entre fases. Saber en plena fase de desarrollo que el tiempo de test se reduce da cierta tranquilidad.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Estos son algunos puntos a favor de TDD. Por supuesto, usarlo implica riesgos. Pero, no usarlo también.&lt;/p&gt;&lt;p&gt;Estáis invitados a dar vuestra opinión al respecto.&lt;/p&gt;&lt;p&gt;Saludos @Madrid&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-5413171057545999226?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/5413171057545999226/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=5413171057545999226' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5413171057545999226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5413171057545999226'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/por-qu-usamos-y-por-qu-no-usamos-tdd.html' title='¿Por qué usamos y por qué no usamos TDD?'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-345467126299701983</id><published>2008-01-16T18:23:00.000+01:00</published><updated>2008-01-16T18:40:45.945+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>Model View Controller Pattern</title><content type='html'>No se como es posible, pero, da igual que la aplicación que se está desarrollando sea de Windows Froms o ASP.NET, siempre aparecen líneas de código en los formularios, que no deberían estar allí.&lt;br /&gt;&lt;br /&gt;Como pone en &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/10/WickedCode/"&gt;este artículo&lt;/a&gt;, esto dificulta testear los métodos de ese formulario (habria que hacerlo a mano). Por ello, debemos intentar separar la capa de presentación de la lógica de negocio.&lt;br /&gt;&lt;br /&gt;Se puede utilizar el MVC (patron modelo-vista-controlador), que permite separar al máximo lo que corresponde al UI, al BL y la interacción entre ambas. Para ayudarnos, se está desarrollando un &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx"&gt;MVC Framework &lt;/a&gt;(que debería haber salido ya, pero no tengo noticias de ello; si alguien las tiene, feedbacks are welcome). la verdad, tengo ganas de que nos llegue ya esa preview para darle un vistacillo, porque muchas veces no usamos este tipo de patrones, simplemente, porque no abemos que existen.&lt;br /&gt;&lt;br /&gt;Aqui teneis un &lt;a href="http://msdn2.microsoft.com/en-us/library/ms998540.aspx"&gt;walkthrough &lt;/a&gt;para implementar MVC sobre ASP.NET y &lt;a href="http://msdn2.microsoft.com/en-us/library/ms998469.aspx"&gt;aquí &lt;/a&gt;la guía dentro de la cual está metida, que tiene un link a la versión PDF, para que lo leais en el metro.&lt;br /&gt;&lt;br /&gt;Un saludo @Madrid&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-345467126299701983?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/345467126299701983/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=345467126299701983' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/345467126299701983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/345467126299701983'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/model-view-controller-pattern.html' title='Model View Controller Pattern'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-8385499900519978324</id><published>2008-01-14T12:09:00.000+01:00</published><updated>2008-01-14T12:27:54.414+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='SPOIL'/><title type='text'>SPOIL: Simplificando el acceso a SQL</title><content type='html'>No te acostarás sin saber una cosa más, pero es que hoy estoy aprendiendo de tirón unas cuantas.&lt;br /&gt;&lt;strong&gt;&lt;em&gt;¿Qué es SPOIL?&lt;/em&gt;&lt;/strong&gt; Son las siglas de Stored Procedure Object Interface Layer&lt;br /&gt;&lt;strong&gt;&lt;em&gt;Vale, pero ¿Que es SPOIL?&lt;/em&gt;&lt;/strong&gt; Vale, lo pillo. SPOIL es algo así como usar el código que otros han escrito y probado, para que tu código sea más sencillo (programación orientada a objetos, vamos). Los chicos de Microsoft se han currado una &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=33dd61e7-2609-46a8-b7e7-a3617eba60ad&amp;amp;displaylang=en"&gt;librería &lt;/a&gt;que hace lo siguiente:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Permite un mapeo más eficaz entre tu DAL y la base de datos (en SQL, eso sí). Esto es, que si tengo que llamar a un SP que se llama Get_LastName y me devuelve el apellido de un usuario a partir de su ID (un entero), bastaría con que creara un método en el DAL con esa firma. Es decir, public string Get_LastName(int ID).&lt;/li&gt;&lt;li&gt;La propia librería se encarga de la converión de parámetros .NET a parámetros SQL. Simplemente hay que especificarle la cadena de conexión y el mapeo de parámetros.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ya sabemos lo que es, pero, ¿es útil?&lt;/em&gt;&lt;/strong&gt; Buena pregunta. He hecho algunas pruebas, pero no lo he usado en ninguna aplicación "real". Parece que se simplifica el mantenimiento, pero SOLO PARA SQL SERVER. Así, nos libramos de arrays conteniendo parámetros de SQL y líneas y líneas inicializándolos. &lt;/p&gt;&lt;p&gt;En contra, parece que se condensa demasiado el código, y a la hora de buscar errores tendremos que analizar en qué punto exacto está fallando (se acabó el típico mensaje de error y que sepas exactamente a qué parámetro se refiere). Además, debemos mantener una coherencia entre la nomenclatura en el código y en la base de datos. Otro contra es que usa Reflection, algo muy útil, pero muy lento. Tendremos que valorar el trabajo que ahorramos - el tiempo de procesador que añadimos.&lt;/p&gt;&lt;p&gt;En cualquier caso, os invito a hacer unas cuantas pruebas. Por lo menos el walkthrough que nos ofrecen en la &lt;a href="http://msdn2.microsoft.com/en-us/library/aa479373.aspx"&gt;MSDN&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Un saludo @Madrid&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-8385499900519978324?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/8385499900519978324/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=8385499900519978324' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8385499900519978324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8385499900519978324'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/spoil-simplificando-el-acceso-sql.html' title='SPOIL: Simplificando el acceso a SQL'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-2363870679538474534</id><published>2008-01-14T10:31:00.000+01:00</published><updated>2008-01-14T10:57:59.724+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Errores Comunes'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Errores comunes (I):"Esta aplicación es demasiado pequeña para desarrollarla por capas"</title><content type='html'>"Esta aplicación es demasiado pequeña para desarrollarla por capas", "Para dos llamadas a base de datos, en vez de usar procedimietnos almacenados, lo escribo a fuego en el código", "Si solo tengo 5 formularios, ¿por qué usar CSS?",...&lt;br /&gt;&lt;br /&gt;Aquí van 3 frases que muchos hemos oído y dicho (me incluyo en ambos grupos, muy a mi pesar). Hay muchas más y la idea de esta sección que hoy se inaugura en este blog es que caigan esos mitos que dicen que "sólo las grandes aplicaciones se desarrollan siguiendo patrones, técnicas para escalabilidad, seguridad...".&lt;br /&gt;&lt;br /&gt;Así que hoy empezamos con la primera&lt;strong&gt;:&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;"Esta aplicación es demasiado pequeña para desarrollarla por capas"&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;¿Quien no ha oído alguna vez esta frase? Generalmente viene acompañada de expresiones como "no tenemos tiempo para andar haciendo capas"... Hombre, si la vida de tu aplicacion es de un par de meses, y se compone exclusivamente de un formulario con dos textBoxes, pues puede que tengas razón. Pero es que la mayoría de las aplicaciones tiene varios formularios, que modifican y leen datos en una base de datos y que procesan algún tipo de información, ¿no?&lt;br /&gt;&lt;br /&gt;Basta con que la aplicación deba acceder a base de datos, para que nos planteemos seriamente meter una capa DAL (Data Access Layer). No hace falta meterla en otro proyecto de la solución. Basta con crear otra clase. Lo importante es que todo esté estructurado.&lt;br /&gt;Puede que mañana, esa aplicación que ahora de basa en Acces, pase a basarse en SQL Server (o MySQL, Oracle...) y entonces tendré que tocar clases que no debería tener que tocar.&lt;br /&gt;Y si trabajo en equipo, la justificación es mucho más obvia. Si el experto en aplicaciones y el experto en bases de datos no es la misma persona, es mejor que esté en dos clases distintas, para que puedan trabajar a la vez. Y si el experto en interfaces no coincide con ninguno de los otros, necesitaremos 3 capas...&lt;br /&gt;&lt;br /&gt;Por capas, no quiero decir que deba estar cada una en una máquina, insisto, sino es simplemente a nivel de organización (podeis dar un ojo a &lt;a href="http://www.lhotka.net/WeBlog/PermaLink.aspx?guid=efa88d0a-2388-4909-bee1-c9bddb6e9868"&gt;este post&lt;/a&gt;, para ver la opinion que suscita la separación física). &lt;a href="http://codebetter.com/blogs/david.hayden/archive/2005/07/23/129745.aspx"&gt;En este artículo&lt;/a&gt;, David Hayden, nos compara también la división en layers y la de tiers, pero además hace un inciso en la importancia del TDD para mantener las aplicaciones divididas en layers y simples.&lt;br /&gt;&lt;br /&gt;¿Cuantas capas debo usar? Bueno, .NET nos permite diferenciar la presentación del código de la página. En caso de que la aplciación sea muy simple, podemos usar ese código para meter la capa de negocio. Pero en caso de que algo, lo que sea, de esa capa de negocio se use en 2 o más formularios, deberíamos usar otra clase aparte. Para el diálogo aplicacion-base de datos, debería haber otra capa. Sirva como truco, que ninguna clase a parte de estas del DAL debería importar ninguna librería que se llame SQL, o JDBC, u Oracle...&lt;br /&gt;&lt;br /&gt;Bueno, la próxima vez intentaremos matar otro de esos mitos que ayudar, lo que se dice ayudar, no ayudan demasiado.&lt;br /&gt;&lt;br /&gt;Un saludo,&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-2363870679538474534?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/2363870679538474534/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=2363870679538474534' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2363870679538474534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2363870679538474534'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/errores-comunes-iesta-aplicacin-es.html' title='Errores comunes (I):&quot;Esta aplicación es demasiado pequeña para desarrollarla por capas&quot;'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-3956026197688335671</id><published>2008-01-14T10:22:00.000+01:00</published><updated>2008-01-14T10:30:08.119+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Los 10 consejos para escribir aplicaciones Web con alto performance</title><content type='html'>Antes de nada, disculparme por lo de "performance", pero no se me ocurría más que "rendimiento" y eso sería una sintesis excesiva y simplona en este caso.&lt;br /&gt;En este artículo, Rob Howard nos da 10 consejos que deberíamos tener en cuenta todos los desarrolladores de aplicaciones Web. Mucho ojito al punto 1 (no se me había ocurrido, pero ya que lo comenta, se me ocurren una barbaridad de aplicaciones junto con la Enterprise Library) y al punto 9 (ya la he usado en alguna aplicación y, si tienes mucho código estático, como css y javascript externo, funciona genial).&lt;br /&gt;&lt;br /&gt;El link es: &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/"&gt;http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ante todo, recomiendo fervientemente hacer caso de uno de los párrafos iniciales:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;strong&gt;you can only learn how to write high-performance Web applications when you're faced with either fixing performance problems or running a high-throughput site.&lt;/strong&gt;&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Algo así como el castizo dicho de "la experiencia es la madre de la ciencia". Cada problema es una oportunidad de aprender, un reto. Y los retos nos hacen crecer (que bonito).&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Un saludo :-) @Madrid&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-3956026197688335671?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/3956026197688335671/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=3956026197688335671' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3956026197688335671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3956026197688335671'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/los-10-consejos-para-escribir.html' title='Los 10 consejos para escribir aplicaciones Web con alto performance'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-7808757072772592459</id><published>2008-01-11T14:22:00.000+01:00</published><updated>2008-01-11T14:37:26.444+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Seguridad'/><title type='text'>Seguridad a nivel de página en ASP.NET</title><content type='html'>Buenas a todos, este es uno de los últimos post desde Madrid, y va a tratar sobre seguridad.&lt;br /&gt;&lt;br /&gt;Cuando planificamos una aplicación, planificamos también quien va a tener acceso a la aplicacion que estamos desarrollando. La posibilidad más extendida es utilizar el web.config para configurar que usuarios van a poder acceder al site y quienes no.&lt;br /&gt;&lt;br /&gt;Sin embargo, aqui vamos a analizar otra posibilidad que permite aplicar una cierta lógica a la autorización, más alla del simple "tú sí", "tú no", más orientada a objetos, pero menos a la escalabilidad que permiten los ficheros de configuración.&lt;br /&gt;&lt;br /&gt;Supongamos que tenemos la página Default.aspx, Pagina1.aspx y Página2.aspx, y que quiero que sólo ciertos usuarios puedan acceder a esas páginas. Es un ejemplo simple que se hace facilmente con el web.config. Pero vamos a hacerlo con herencia.&lt;br /&gt;&lt;br /&gt;Creamos una clase que se llame BasePage.cs, que herede de Page. Sobreescribimos el evento Init de la página, que nos permitirá ejecutar las acciones que queramos antes si quiera de que se genere el formulario.&lt;br /&gt;&lt;br /&gt;La página quedaría así:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public class BasePage : Page&lt;br /&gt;{&lt;br /&gt;public BasePage() { }&lt;br /&gt;protected sealed override void OnInit(EventArgs e)&lt;br /&gt;{&lt;br /&gt; if (!ValidateAccess()) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;   throw new System.Security.Authentication.AuthenticationException();&lt;br /&gt; base.OnInit(e);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;private bool ValidateAccess()&lt;br /&gt; {&lt;br /&gt;  WindowsIdentity identidad = WindowsIdentity.GetCurrent();&lt;br /&gt;  return (identidad.Name.Contains("nombreUsuario"));&lt;br /&gt; }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Por supuesto, en el método ValidateAccess podríamos meter tanta lógica como quisieramos. Podríamos acceder a base de datos para comprobar si ese usuario tiene permiso para acceder en este momento a esa página, por ejemplo.&lt;br /&gt;&lt;br /&gt;A partir de aqui, todas las páginas que hereden de esta clase, ejecutarán esa validación en el Init. Además, puesto que hemos incorporado la clausula "&lt;span style="font-family:courier new;"&gt;sealed&lt;/span&gt;", las páginas que hereden de nuestra clase no podran sobreescribir el método.&lt;br /&gt;&lt;br /&gt;¿Y si el comportamiento no es el mismo para todas las páginas? Bueno, es más que probable que unas páginas tengan una lógica determinada, otras otra. Bastará con crear tantas clases como BasePage como criterios de seguridad tengamos y hacer heredar cada página de su correspondiente base.&lt;br /&gt;&lt;br /&gt;Otra mejora consistiria en hacer el metodo ValidateAccess "&lt;span style="font-family:courier new;"&gt;virtual&lt;/span&gt;" para que cada página personalice su método para la validación.&lt;br /&gt;&lt;br /&gt;Por supuesto, esto no debe aplicarse sin más. Hay ue analizar si es mejor este metodo que usar una distribución en carpetas, cada una con su Web.config. Queda a criterio del desarrolador.&lt;br /&gt;&lt;br /&gt;Un saludo a todos :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-7808757072772592459?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/7808757072772592459/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=7808757072772592459' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7808757072772592459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7808757072772592459'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2008/01/seguridad-nivel-de-pgina-en-aspnet.html' title='Seguridad a nivel de página en ASP.NET'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-6412978733829946727</id><published>2007-11-19T11:46:00.001+01:00</published><updated>2007-11-19T11:52:27.617+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>Generar scripts para carga de datos</title><content type='html'>Buenas a todos, antes de nada, disculpas por la ausencia pero he andado bastante liadillo... Aprovecho para mandar un saludo a Jaime y los dos David, especialmente al primero que es el que mantiene vivo esto en los últimos meses. Gracias.&lt;br /&gt;&lt;br /&gt;Al tema. ¿Cuantas veces hemos tenido que preparar un paso a producción y nos ha tocado preparar los scripts para Sql Server 2005? Vale, es facil, si usamos la opción de Tasks--&gt;Generate Scripts del SqlServer. Bien, pero... ¿y los datos? ¿y todas esas tablas de 1000 o más registros que nos ha llevado semanas ir rellenando? ¿Les damos a los encargados del paso a produccion una copia del excel con los datos y les decimos que copien y peguen?&lt;br /&gt;&lt;br /&gt;Bueno, si elegis esa opcion, aseguraos de tener zapatillas deportivas y buena forma física, porque os van a dar yoyas hasta en la sopa.&lt;br /&gt;&lt;br /&gt;Por eso os mando un link (y me lo mando a mi mismo), que genera un procedimiento almacenado que se ejecuta contra las tablas y nos devuelve un insert por cada fila. Luego la copiamos a un fichero .sql y todos tan contentos.&lt;br /&gt;&lt;br /&gt;Lo han hecho nuestros amigos de CodeProject: &lt;a href="http://www.codeproject.com/database/InsertGeneratorPack.asp"&gt;http://www.codeproject.com/database/InsertGeneratorPack.asp&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Espero que os sirva de algo...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-6412978733829946727?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/6412978733829946727/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=6412978733829946727' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/6412978733829946727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/6412978733829946727'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/11/generar-scripts-para-carga-de-datos.html' title='Generar scripts para carga de datos'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-2794869748245241065</id><published>2007-10-31T09:24:00.000+01:00</published><updated>2007-10-31T10:04:54.281+01:00</updated><title type='text'>VSS Remover</title><content type='html'>Antes de nada un saludo a mis amigos Jesus, David y David. Espero que todo os vaya genial, tenemos que quedar para charlar algun dia no? digooooooooo&lt;br /&gt;&lt;br /&gt;Bueno, la idea de este post es crear un programilla en C# para quitar las referencias que deja el Source Safe en nuestras soluciones/projectos. He estado leyendo cositas y generalmente la gente lo hace a mano porque unicamente lo tiene que quitar de una solucion con un par de proyectos. Pero, que pasa cuando tenemos... unas 10 soluciones con, digamos tres proyectos cada una? pues que ni te lo piensas, hay que automatizarlo de alguna manera.&lt;br /&gt;&lt;br /&gt;Estos son los pasos que he seguido para quitar el binding:&lt;br /&gt;1 - Go to the folder containing the solution files and delete the following:&lt;br /&gt;          mssccprj.scc&lt;br /&gt;          MyProject.vssscc&lt;br /&gt;          vssver.scc&lt;br /&gt;&lt;br /&gt;2 - Open MyProject.sln in your favorite text editor and remove the following section:&lt;br /&gt;          GlobalSection(SourceCodeControl) = preSolution&lt;br /&gt;                     ...&lt;br /&gt;          EndGlobalSection&lt;br /&gt;&lt;br /&gt;3 - Go to the folder containing the project files and delete the following:&lt;br /&gt;          MyProject.vbproj.vspscc&lt;br /&gt;          mssccprj.scc&lt;br /&gt;          vssver.scc&lt;br /&gt;&lt;br /&gt;4 - Open MyProject.vbproj in your text editor and remove the following lines:&lt;br /&gt;          SccProjectName = "SAK"&lt;br /&gt;          SccLocalPath = "SAK"&lt;br /&gt;          SccAuxPath = "SAK"&lt;br /&gt;          SccProvider = "SAK"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Parece que no pero pero recorrerte toda la estructura de carpetas haciendo esto tiene que ser fatal asi que utilizamos un metodo loopDir para recorrerlo y dos funciones removeSolutionBinding y removeProjectBinding para quitar el texto que hace referencia al vss dentro de los ficheros .sln y .csproj:&lt;br /&gt;&lt;br /&gt; private static void loopDir(string dir)&lt;br /&gt;        {&lt;br /&gt;            string[] dirs = Directory.GetDirectories(dir);&lt;br /&gt;            string[] files = Directory.GetFiles(dir);&lt;br /&gt;            &lt;br /&gt;            foreach (string s in files)&lt;br /&gt;            {&lt;br /&gt;                File.SetAttributes(s, FileAttributes.Normal);&lt;br /&gt;                if (Path.GetExtension(s) == ".sln" || Path.GetExtension(s)== ".csproj" || Path.GetExtension(s) == ".vbproj")&lt;br /&gt;                {&lt;br /&gt;                    removeBinding(s);&lt;br /&gt;                }&lt;br /&gt;                else if (Path.GetExtension(s) == ".scc" ||Path.GetExtension(s) == ".vssscc" || Path.GetExtension(s) == ".vspscc")&lt;br /&gt;                {&lt;br /&gt;                    File.Delete(s);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;            // loop subdirs&lt;br /&gt;            if (dirs.Length &gt; 0)&lt;br /&gt;            {&lt;br /&gt;                foreach (string d in dirs)&lt;br /&gt;                {&lt;br /&gt;                    // call this method again&lt;br /&gt;                    loopDir(d);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;De esta manera recorremos el arbol de carpetas. Si nos encontramos un fichero de solucion o proyecto llamamos a eliminar binding y sino, si es un fichero de los que hay que eliminar pues lo borramos directamente.&lt;br /&gt;Aqui estan las funciones de eliminar binding:&lt;br /&gt;&lt;br /&gt; private static void removeBinding(string f)&lt;br /&gt;        {&lt;br /&gt;            switch (Path.GetExtension(f))&lt;br /&gt;            {&lt;br /&gt;                case ".sln":&lt;br /&gt;                    removeSolutionBinding(f);&lt;br /&gt;                    break;&lt;br /&gt;                default:&lt;br /&gt;                    removeProjectBinding(f);&lt;br /&gt;                    break;&lt;br /&gt;               &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void removeSolutionBinding(string s)&lt;br /&gt;        {&lt;br /&gt;            string line = string.Empty;&lt;br /&gt;            bool flag = false;&lt;br /&gt;            FileStream fs = new FileStream(s + ".temp", FileMode.CreateNew);&lt;br /&gt;            System.IO.StreamWriter sw = new StreamWriter(fs);&lt;br /&gt;            //Create reader&lt;br /&gt;            System.IO.StreamReader sr = new System.IO.StreamReader(s);&lt;br /&gt;            while (sr.Peek() != -1)&lt;br /&gt;            {&lt;br /&gt;                line = sr.ReadLine();&lt;br /&gt;                if (line.IndexOf("GlobalSection(SourceCodeControl)") == -1 &amp;&amp; !flag)&lt;br /&gt;                    sw.WriteLine(line);&lt;br /&gt;                else&lt;br /&gt;                    //do not write endglobalsection line&lt;br /&gt;                    flag = (line.IndexOf("EndGlobalSection") == -1);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            sr.Close();&lt;br /&gt;            sw.Close();&lt;br /&gt;            &lt;br /&gt;            File.Copy(fs.Name, s, true);&lt;br /&gt;            File.Delete(fs.Name);&lt;br /&gt;&lt;br /&gt;            fs.Close();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void removeProjectBinding(string s)&lt;br /&gt;        {&lt;br /&gt;            string line = string.Empty;&lt;br /&gt;            bool flag = false;&lt;br /&gt;            FileStream fs = new FileStream(s + ".temp", FileMode.CreateNew);&lt;br /&gt;            System.IO.StreamWriter sw = new StreamWriter(fs);&lt;br /&gt;            //Create reader&lt;br /&gt;            System.IO.StreamReader sr = new System.IO.StreamReader(s);&lt;br /&gt;            while (sr.Peek() != -1)&lt;br /&gt;            {&lt;br /&gt;                line = sr.ReadLine();&lt;br /&gt;                if (line.IndexOf("SccProjectName") == -1 &amp;&amp; !flag)&lt;br /&gt;                    sw.WriteLine(line);&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    flag = (line.IndexOf("&gt;") == -1);&lt;br /&gt;                    //need to write symbol "&gt;" to close the tag&lt;br /&gt;                    if (!flag) sw.WriteLine(line);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            sr.Close();&lt;br /&gt;            sw.Close();&lt;br /&gt;            &lt;br /&gt;            File.Copy(fs.Name, s, true);&lt;br /&gt;            File.Delete(fs.Name);&lt;br /&gt;&lt;br /&gt;            fs.Close();&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;Unicamente comentar que si tenemos la solucion y todos los projectos en el mismo arbol de directorios todo irá como la seda pero recordad que a veces para montar nuestras aplicaciones en local los projectos web están ubicados en wwwroot por lo que tendreis que seleccionar dentro de wwwroot la carpeta de vuestro projecto para quitar tambien el binding de ahí.&lt;br /&gt;&lt;br /&gt;Un saludo amigos ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-2794869748245241065?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/2794869748245241065/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=2794869748245241065' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2794869748245241065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2794869748245241065'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/10/vss-remover.html' title='VSS Remover'/><author><name>Kiumo</name><uri>http://www.blogger.com/profile/12411626320891648452</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-2933807786490189421</id><published>2007-06-24T21:35:00.000+02:00</published><updated>2007-06-24T22:48:40.149+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Como configurar un WebSite con autenticacion 'Forms' y dos paginas de Login.</title><content type='html'>Bueno, lo primero saludar a mis amigos Jesús, David y David ;) que me han dejado un sitio en su blog para poder publicar cositas interesantes.&lt;br /&gt;&lt;br /&gt;Vamos allá. Lo que necesitamos esta vez es tener un web site al que puedan acceder dos tipos de usuarios distintos a dos partes del site diferenciadas pero dentro de la misma aplicacion. Imaginemos un tipo de usuario alumno y un tipo de usuario centro. Los alumnos se pueden conectar para ver sus notas y los centros se pueden conectar para ver los alumnos que se han presentado a cada examen y las notas que han sacado de tal manera que compaten base de datos. Ahora nos preguntaremos, para que queremos un web site con dos accesos diferentes?, será mejor hacer dos web sites no? uno para cada tipo de usuario, con sus paginas y sus rollos no? pues si! pero..., jeje, el cliente lo quiere así y así lo tenemos que hacer.&lt;br /&gt;&lt;br /&gt;La solucion que se nos ocurre a bote pronto es organizar el site en dos partes, una para alumnos y otra para centros. A nivel de root crear un web.config con la configuracion global y luego una carpeta para cada una de las partes con su propio web.config .&lt;br /&gt;Hasta aqui todo bien, ponemos en el root el web.config y declaramos que la autenticacion va a ser del tipo 'Forms' y que redireccione a una pagina de login que pondremos en la raiz del site:&lt;br /&gt;&lt;br /&gt;&amp;lt;authentication mode="Forms"&amp;gt;&lt;br /&gt;&amp;lt;forms name=".cookiename" timeout="20" protection="All" loginurl="login.aspx"&amp;gt;&lt;br /&gt;&amp;lt;/authentication&amp;gt;&lt;br /&gt;&lt;br /&gt;Ahora si intentamos poner la misma tag en el web.config de la carpeta alumnos para que redireccione a loginalumnos.aspx tachan!!!! application error:&lt;br /&gt;It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.&lt;br /&gt;Esto es debido a que solo se puede declarar el tag authentication a nivel de aplicacion (en el web.config del root) y una sola vez.&lt;br /&gt;Vaya por dios, entonces? como hacemos? si queremos tener dos paginas de login!.&lt;br /&gt;&lt;br /&gt;Bueno pues tendremos que hacerlo de alguna manera que nos permita redireccionar desde la pagina login del root a cada una de las paginas de login dependiendo a donde queramos acceder. Una vez authenticados, crearemos un rol para el usuario (si es alumno 'Alumno' y si es centro 'Centro') y solo dejaremos acceder a las páginas dependiendo de este rol.&lt;br /&gt;Para hacer esto, unicamente tendremos que agregar el tag de autorizacion a cada uno de los web.config:&lt;br /&gt;Para la carpeta de alumnos:&lt;br /&gt;&amp;lt;authorization&amp;gt;&lt;br /&gt;&amp;lt;allow roles="Alumno"&amp;gt;&lt;br /&gt;&amp;lt;deny users="*"&amp;gt;&lt;br /&gt;&amp;lt;/authorization&amp;gt;&lt;br /&gt;Para la carpeta de centros:&lt;br /&gt;&amp;lt;authorization&amp;gt;&lt;br /&gt;&amp;lt;allow roles="Centro"&amp;gt;&lt;br /&gt;&amp;lt;deny users="*"&amp;gt;&lt;br /&gt;&amp;lt;/authorization&amp;gt;&lt;br /&gt;&lt;br /&gt;Además, para completar el web.config tendremos que añadir las tag "location path=" para todas las paginas que queramos que puedan acceder tanto usuarios registrados como anónimos (en este caso para la de login y para la de help). Si no ponemos esto, no nos dejaría entrar en la pagina de login porque no tenemos el rol correspondiente.&lt;br /&gt;&lt;br /&gt;&amp;lt;location path="Login.aspx"&amp;gt;&lt;br /&gt;  &amp;lt;system.web&amp;gt;&lt;br /&gt;   &amp;lt;authorization&amp;gt;&lt;br /&gt;    &amp;lt;allow users="*"/&amp;gt;&lt;br /&gt;    &amp;lt;allow users="?"/&amp;gt;&lt;br /&gt;   &amp;lt;/authorization&amp;gt;&lt;br /&gt;  &amp;lt;/system.web&amp;gt;&lt;br /&gt; &amp;lt;/location&amp;gt;&lt;br /&gt; &amp;lt;location path="Help.aspx"&amp;gt;&lt;br /&gt;  &amp;lt;system.web&amp;gt;&lt;br /&gt;   &amp;lt;authorization&amp;gt;&lt;br /&gt;    &amp;lt;allow users="?"/&amp;gt;&lt;br /&gt;   &amp;lt;/authorization&amp;gt;&lt;br /&gt;  &amp;lt;/system.web&amp;gt;&lt;br /&gt; &amp;lt;/location&amp;gt;&lt;br /&gt;&lt;br /&gt;Ahora en la pagina de login,depues de comprobar que el usuario y pass son correctos, tendremos que añadir el rol:&lt;br /&gt;&lt;br /&gt;public void CreateNewMemberTicket(string username, Role userRole, bool persistent)&lt;br /&gt;{&lt;br /&gt;//get user roles&lt;br /&gt;string role = GetRoleName(userRole);&lt;br /&gt;// Create a new ticket used for authentication&lt;br /&gt;FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(&lt;br /&gt;1, // Ticket version&lt;br /&gt;username, // Username associated with ticket&lt;br /&gt;DateTime.Now, // Date/time issued&lt;br /&gt;DateTime.Now.AddMinutes(20), // Date/time to expire&lt;br /&gt;persistent, // "false" for a non persistent user cookie&lt;br /&gt;role, // User-data, in this case the roles&lt;br /&gt;FormsAuthentication.FormsCookiePath);// Path cookie valid for&lt;br /&gt;// Encrypt the cookie using the machine key for secure transport&lt;br /&gt;string hash = FormsAuthentication.Encrypt(ticket);&lt;br /&gt;HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, // Name of auth cookie&lt;br /&gt;hash); // Hashed ticket&lt;br /&gt;// Set the cookie's expiration time to the tickets expiration time&lt;br /&gt;if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;&lt;br /&gt;// Add the cookie to the list for outgoing response&lt;br /&gt;Response.Cookies.Add(cookie);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Con esto conseguimos añadir a la cookie de authenticacion el rol del usuario. Ya solo nos queda crearnos el objeto GenericPrincipal para que el usuario que está logeado pueda ver la pagina que solicita al servidor, es decir, despues de logearse si va a la pagina alumnohome.aspx tendremos que asegurarnos que el rol que tiene el usuario en ese momento es el de 'Alumno' y sino redireccionarlo a la pagina de login. &lt;br /&gt;&lt;br /&gt;Esto lo hacemos en el metodo Application_AuthenticateRequest de la Global.asax (si no la tenemos la añadimos al website)&lt;br /&gt;&lt;br /&gt;protected void Application_AuthenticateRequest(Object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;     if (HttpContext.Current.User != null)&lt;br /&gt; {&lt;br /&gt;  if (HttpContext.Current.User.Identity.IsAuthenticated)&lt;br /&gt;    {&lt;br /&gt;   if (HttpContext.Current.User.Identity is FormsIdentity)&lt;br /&gt;   {&lt;br /&gt;  FormsIdentity id =(FormsIdentity)HttpContext.Current.User.Identity;&lt;br /&gt;  FormsAuthenticationTicket ticket = id.Ticket;&lt;br /&gt;&lt;br /&gt;  // Get the stored user-data, in this case, the roles&lt;br /&gt;  string userData = ticket.UserData;&lt;br /&gt;  HttpContext.Current.User = new GenericPrincipal(id,roles);&lt;br /&gt;   }&lt;br /&gt;    }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;En la pagina de login del root debemos tambien redirigir a la de login de alumno o centro:&lt;br /&gt;&lt;br /&gt;protected override void OnInit(EventArgs eventArgs)&lt;br /&gt;  {&lt;br /&gt;                &lt;br /&gt;   string returnvalue = Request.QueryString.Get("ReturnUrl").ToLower();&lt;br /&gt;   if(returnvalue != null)&lt;br /&gt;   {&lt;br /&gt;    &lt;br /&gt;    if(returnvalue.IndexOf("/alumnos/") != -1)&lt;br /&gt;    {&lt;br /&gt;     Server.Transfer("~/alumnos/Login.aspx");&lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;    else if (returnvalue.IndexOf("/centros/") != -1)&lt;br /&gt;    {&lt;br /&gt;     Server.Transfer("~/centros/Login.aspx") &lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   base.OnInit(eventArgs);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;HTH jeje,&lt;br /&gt;&lt;br /&gt;Un saludo desde tierras del norte! Cuidaros ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-2933807786490189421?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/2933807786490189421/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=2933807786490189421' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2933807786490189421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2933807786490189421'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/06/como-configurar-un-website-con.html' title='Como configurar un WebSite con autenticacion &apos;Forms&apos; y dos paginas de Login.'/><author><name>Kiumo</name><uri>http://www.blogger.com/profile/12411626320891648452</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-9068335582496922052</id><published>2007-05-31T17:06:00.000+02:00</published><updated>2007-05-31T17:09:01.775+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD (El test antes del código) (y 3)</title><content type='html'>Cogemos el test 1: Dado un -1 (ejemplo de entero negativo) y 2 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 2)&lt;br /&gt;&lt;br /&gt;Codificamos el test:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using NUnit.Framework;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[TestFixture]&lt;br /&gt;public class CalculadoraTest&lt;br /&gt;{&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_001()&lt;br /&gt;        {&lt;br /&gt;            Calculadora calc = new Calculadora();&lt;br /&gt;            calc.sumar(-1, 1);&lt;br /&gt;        }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Y codificamos lo mínimo para que funcione el test (que funcione no significa que pase):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El tets falla. Evidente, no? Esperabamos una excepción y hemos recibido un 0. Rehacemos el código hasta que pase el test.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        if (a &lt; 0)&lt;br /&gt;            throw new Exception();&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora pasa. Perfecto. Cogemos el segundo test.&lt;br /&gt;&lt;br /&gt;Dado un 1 (ejemplo de entero positivo) y un -1 (ejemplo de entero negativo), obtenemos una excepción (cumplimos la regla de negocio 2)&lt;br /&gt;&lt;br /&gt;Codificamos el test, comprobamos que falla…&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;[Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_002()&lt;br /&gt;    {&lt;br /&gt;        Calculadora calc = new Calculadora();&lt;br /&gt;        calc.sumar(1, -1);&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y cambiamos el código para que también soporte este caso.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        if (a &lt; 0  b &lt;0)&lt;br /&gt;            throw new Exception();&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora pasa. Genial, pero no hemos acabado. Lanzamos de nuevo TODOS los tests para ver que el cambio no rompe algo que funcionaba.&lt;br /&gt;¿Funcionan? Si, genial. Antes de ir al siguiente código, miramos a ver si se puede refactorizar algo…&lt;br /&gt;¿Crees que aún es pronto? ¿Qué hay pocas líneas? Jaja Vemos que en los dos tests que hay hasta ahora, creamos un objeto Calculadora. Podríamos sacarlo de allí y meterlo a nivel general.&lt;br /&gt;El código quedaría así:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;[TestFixture]&lt;br /&gt;public class CalculadoraTest&lt;br /&gt;{&lt;br /&gt;    Calculadora calc;&lt;br /&gt;&lt;br /&gt;    [TestFixtureSetUp]&lt;br /&gt;    public void Init()&lt;br /&gt;    {&lt;br /&gt;        calc = new Calculadora();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_001()&lt;br /&gt;    {&lt;br /&gt;        calc.sumar(-1, 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_002()&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        calc.sumar(1, -1);&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cogemos el test 3: Dado un 1 (ejemplo de entero positivo) y un 3 (ejemplo de entero positivo), obtenemos un 4 (cumplimos la regla de negocio 1 y la 3). Repetimos los pasos anteriores…&lt;br /&gt;&lt;br /&gt;Y falla… Bueno, corregimos el código para que pase (OJO a la jugada). Vamos a hacer que siempre devuelva un 4 (salvo que alguno sea negativo).&lt;br /&gt;&lt;br /&gt;El test queda:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;[Test]&lt;br /&gt;    public void Calculadora_Test_003()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 3) == 4);&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y el código queda:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        if (a &lt; 0  b &lt;0)&lt;br /&gt;            throw new Exception();&lt;br /&gt;        return 4;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Parece que la jugada no tiene sentido, pero paciencia. De momento, no hemos metido ni una función demás en el código. Hace lo que le piden los test. Ni más, ni menos.&lt;br /&gt;&lt;br /&gt;Cogemos el 4º test. Dado un 0 (ejemplo de frontera) y un 1 (ejemplo de entero positivo), obtenemos un 1 (cumplimos la regla de negocio 1 y la 3). Repetimos el proceso.&lt;br /&gt;Ahora hacemos que devuelva siempre 2.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        if (a &lt; 0  b &lt;0)&lt;br /&gt;            throw new Exception();&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El test pasa pero si ejecutamos todos no. Es ahora cuando metemos el a + b.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Y pasan todos los test… genial.&lt;br /&gt;&lt;br /&gt;Y así sucesivamente hasta el test 7 (incluido). Pasar estos tests no requerirá cambios en el código de la calculadora, pero el 8º sí.&lt;br /&gt;&lt;br /&gt;Dado un 10001 (ejemplo de frontera numero grande) y 1 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 4). Esto requiere que metamos otra rama en los primeros IF.&lt;br /&gt;&lt;br /&gt;Y así sucesivamente… nuevo test, que pase, refactorizamos, nuevo test, que pase, refactorizamos, nuevo test, que pase, refactorizamos, …&lt;br /&gt;&lt;br /&gt;Al final nos queda la clase de test así:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;[TestFixture]&lt;br /&gt;public class CalculadoraTest&lt;br /&gt;{&lt;br /&gt;    Calculadora calc;&lt;br /&gt;&lt;br /&gt;    [TestFixtureSetUp]&lt;br /&gt;    public void Init()&lt;br /&gt;    {&lt;br /&gt;        calc = new Calculadora();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_001()&lt;br /&gt;    {&lt;br /&gt;        calc.sumar(-1, 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_002()&lt;br /&gt;    {&lt;br /&gt;        calc.sumar(1, -1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_003()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 3) == 4);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_004()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 1) == 2);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_005()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 0) == 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_006()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(10000, 1) == 10001);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_007()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 10000) == 10001);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_008()&lt;br /&gt;    {&lt;br /&gt;        calc.sumar(10001, 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test, ExpectedException()]&lt;br /&gt;    public void Calculadora_Test_009()&lt;br /&gt;    {&lt;br /&gt;        calc.sumar(1, 10001);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_010()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(9999, 1) == 10000);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Calculadora_Test_011()&lt;br /&gt;    {&lt;br /&gt;        Assert.IsTrue(calc.sumar(1, 9999) == 10000);&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Y el código…&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;public int sumar(int a, int b)&lt;br /&gt;    {&lt;br /&gt;        if (a &lt;&gt; 10000  a &gt; 10000)&lt;br /&gt;            throw new Exception();&lt;br /&gt;        return a + b;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Curioso que hayamos dedicado más de 50 líneas para testear 3, no? Puede parecer poco rentable, pero AHORA SABEMOS QUE EL CÓDIGO FUNCIONA Y CUMPLE LAS REGLAS DE NEGOCIO. A PARTIR DE AHORA, SI AÑADIMOS MÁS CÓDIGO, SABREMOS QUE EL FALLO ES DE LO QUE VAYAMOS AÑADIENDO, PORQUE EL CÓDIGO DE A SUMA, ESTÁ PROBADO.&lt;br /&gt;&lt;br /&gt;Un saludo&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-9068335582496922052?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/9068335582496922052/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=9068335582496922052' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/9068335582496922052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/9068335582496922052'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/tdd-el-test-antes-del-cdigo-y-3.html' title='TDD (El test antes del código) (y 3)'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-4728414345113044161</id><published>2007-05-31T17:03:00.000+02:00</published><updated>2007-05-31T17:05:45.632+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD (El test antes del código) (2)</title><content type='html'>Vamos a hacer un ejemplo sencillo. Una calculadora que suma y resta.&lt;br /&gt;Primero, analizamos las reglas de negocio.&lt;br /&gt;1-      Dados dos numeros, debe sumarlos o restarlos.&lt;br /&gt;2-      Los numeros deben ser enteros y positivos.&lt;br /&gt;3-      El resultado debe ser también entero y positivo&lt;br /&gt;4-      La entrada no puede tener ningún valor mayor que 10000&lt;br /&gt;&lt;br /&gt;Segundo. La lista de test. Nos tomamos nuestro tiempo para hacerla.&lt;br /&gt;Vamos a verificar también que cumplimos las reglas de negocio.&lt;br /&gt;&lt;br /&gt;Antes de hacer la lista, es conveniente hacer una lista de valores frontera que pueden ser causantes de problemas o, por una u otra razón, tienen alguna importancia.&lt;br /&gt;&lt;br /&gt;En este caso, los valores frontera serían: 0 (por ser el límite entre positivos y negativos, que mencionan las reglas de negocio 2 y 3), 10000 (para comprobar la regla de negocio 4) y -1 y 1, por ser el anterior y el posterior al valor frontera 0 y 10001 y 9999, por ser el anterior y el posterior al valor frontera 10000.&lt;br /&gt;&lt;br /&gt;Analizamos también que facetas de IDE de Visual Studio hacen que no tengamos que testear algunas reglas. Por ejemplo, no deberemos testear que pasaría si metemos un número decimal, pues el método SUMA no admitirá esos valores y fallará por sí mismo.&lt;br /&gt;&lt;br /&gt;Lista de Test para la SUMA&lt;br /&gt;(1) Dado un -1 (ejemplo de entero negativo) y 2 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 2)&lt;br /&gt;(2)  Dado un 1 (ejemplo de entero positivo) y un -1 (ejemplo de entero negativo), obtenemos una excepción (cumplimos la regla de negocio 2)&lt;br /&gt;(3) Dado un 1 (ejemplo de entero positivo) y un 3 (ejemplo de entero positivo), obtenemos un 4 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(4) Dado un 0 (ejemplo de frontera) y un 1 (ejemplo de entero positivo), obtenemos un 1 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(5) Dado un 1 (ejemplo de entero positivo) y un 0 (ejemplo de frontera), obtenemos un 1 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(6) Dado un 10000 (ejemplo de numero grande) y 1 (ejemplo de entero positivo), obtenemos 10001 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(7)  Dado un 1 (ejemplo de entero positivo) y 10000 (ejemplo de numero grande), obtenemos 10001 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(8) Dado un 10001 (ejemplo de frontera numero grande) y 1 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 4)&lt;br /&gt;(9) Dado 1 (ejemplo de entero positivo) y un 10001 (ejemplo de frontera de numero grande), obtenemos una excepción (cumplimos la regla de negocio 4)&lt;br /&gt;(10) Dado un 1 (ejemplo de entero positivo) y 9999(ejemplo de frontera de numero grande), obtenemos 10000 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;(11) Dado un 9999(ejemplo de frontera de numero grande) y un 1 (ejemplo de entero positivo, obtenemos 10000 (cumplimos la regla de negocio 1 y la 3)&lt;br /&gt;&lt;br /&gt;No cerramos la lista, porque si encontramos algún otro test, lo añadiremos.&lt;br /&gt;&lt;br /&gt;A programar!!!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-4728414345113044161?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/4728414345113044161/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=4728414345113044161' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/4728414345113044161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/4728414345113044161'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/tdd-el-test-antes-del-cdigo-2.html' title='TDD (El test antes del código) (2)'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-7788479048685117437</id><published>2007-05-31T17:02:00.000+02:00</published><updated>2007-05-31T17:03:41.750+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD (El test antes del código) (1)</title><content type='html'>¿Qué es TDD?&lt;br /&gt;&lt;br /&gt;TDD son las siglas de Test Driven Development (desarrollo guiado por pruebas), que no es más que una manera de tirar código basandonos en los resultados que debe dar.&lt;br /&gt;Es una de las técnicas del eXtremme Programming, y tiene bastantes ventajas e inconvenientes.&lt;br /&gt;Las ventajas:&lt;br /&gt;El código es más fiable al estar más sometido a tests que el código normal.&lt;br /&gt;Se desarrolla el código justo para que funcione. No se tiran lineas que no aporten valor.&lt;br /&gt;Ahorramos tiempo en fases posteriores a la de build.&lt;br /&gt;&lt;br /&gt;Los inconvenientes&lt;br /&gt;La lista de tests con la que contamos debe ser lo más completa posible. Eso requiere conocer muy bien las reglas de negocio.&lt;br /&gt;Hay que tener una cierta experiencia a la hora de desarrollar, que permita completar las (casi siempre) incompletas listas de tests.&lt;br /&gt;Alarga la fase de build (acorta las posteriores), lo que no siempre se entiende en los proyectos.&lt;br /&gt;&lt;br /&gt;El proceso para desarrollar con TDD sería:&lt;br /&gt;(1)   Analizar las reglas de negocio.&lt;br /&gt;(2)   Obtener una primera lista de tests (mala señal si es la definitiva) con lo que deberíamos obtener ante una serie de datos de entrada.&lt;br /&gt;(3)   Codificamos el primer test, lo lanzamos y comprobamos que el test falla.&lt;br /&gt;(4)   Codificamos lo justo para que el test pase y lo comprobamos.&lt;br /&gt;(5)   Pasamos al siguiente test.&lt;br /&gt;(6)   Lo codificamos, lo lanzamos y comprobamos que falla.&lt;br /&gt;(7)   Codificamos lo justo para pasar este test y comprobamos que pasa.&lt;br /&gt;(8)   Comprobamos que pasan TODOS los tests hasta ahora, por si hemos roto algo.&lt;br /&gt;(9)   Refactorizamos el código (en el test y el código)&lt;br /&gt;(10)                       Volvemos a 5&lt;br /&gt;&lt;br /&gt;Importante: si creemos que son necesarios más tests, porque hay situaciones que no hemos comprobado, añadimos los tests. No hay que tener miedo a corregir, sino a pensar que está bien algo que no lo está.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-7788479048685117437?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/7788479048685117437/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=7788479048685117437' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7788479048685117437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7788479048685117437'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/tdd-el-test-antes-del-cdigo-1.html' title='TDD (El test antes del código) (1)'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-1173491363844079539</id><published>2007-05-30T15:49:00.000+02:00</published><updated>2007-05-30T15:52:37.040+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>SQL Server 2005 y el tipo de datos XML: Configuración del esquema</title><content type='html'>&lt;strong&gt;Escenario inicial&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Tenemos una tabla donde una (o más) de las columnas son de tipo XML&lt;br /&gt;Queremos crear un esquema que represente el contenido de esa columna para acelerar las queries que vayan contra esa columna.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Procedimiento&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Cogemos un XML que sea representativo, que tenga todos los campos que vamos a necesitar.&lt;br /&gt;Guardamos el fichero en disco.&lt;br /&gt;Usando la aplicación XSD (Visual Studio Tools a Visual Studio 2005 Command Prompt) ejecutamos el comando XSD [nombre_fichero.xml]&lt;br /&gt; &lt;br /&gt;&lt;em&gt;Nota: es posible que de fallos porque haya caracteres extraños. Hay que quitar las Ñ, %, $, €, …&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;Abro el fichero que se ha generado (misma ruta y nombre que el origen, pero con XSD de extensión) con el Notepad.&lt;br /&gt;El contenido es el esquema del XML elegido.&lt;br /&gt;Voy al SQL Server 2005 y hago una nueva query:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;IF EXISTS (SELECT *&lt;br /&gt;             FROM sys.xml_schema_collections&lt;br /&gt;            WHERE name = N'mySchema')&lt;br /&gt;DROP XML SCHEMA COLLECTION mySchema&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE XML SCHEMA COLLECTION mySchema&lt;br /&gt;AS&lt;br /&gt;'&lt;br /&gt;CONTENIDO DEL FICHERO XSD&lt;br /&gt;'&lt;br /&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Donde pone CONTENIDO DEL FICHERO XSD, meto el contenido del XSD.&lt;br /&gt;&lt;br /&gt;Ejecuto la query. Si todo ha ido bien, se habrá añadido a la lista de esquemas de SQL Server.&lt;br /&gt;Voy a la tabla, con el fin de modificarla. Voy a la columna XML y en propiedades, configuro la sección de XML.&lt;br /&gt;&lt;br /&gt;Elijo el esquema que acabo de crear, del combo de Schema Collection y configuro Is XML Document como Yes.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Nota: si no aparece es posible que haya fallado el refresco. Cerramos la pestaña y la volvemos a abrir.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Damos a guardar los cambios de la tabla. Si todos los XML que estén presentes (si los hay) concuerdan con el esquema, no habrá problema y se guardará. Si alguno no concuerda, habra que hacer modificaciones en el esquema para que encaje. Uno de los posibles cambios que, seguramente, habrá que hacer, es distribuir los elementos simples (que no tienen sub-elementos), ya que la herramienta XSD suele colocarlos juntos al crear el esquema. De todas maneras, en los errores que da al guardar, nos indica qué campos esperaba encontrar y cuales ha encontrado realmente.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-1173491363844079539?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/1173491363844079539/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=1173491363844079539' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/1173491363844079539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/1173491363844079539'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/sql-server-2005-y-el-tipo-de-datos-xml.html' title='SQL Server 2005 y el tipo de datos XML: Configuración del esquema'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-7515459301482671782</id><published>2007-05-30T15:45:00.000+02:00</published><updated>2007-05-30T15:46:57.147+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Queries'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>Documentando nuestra base de datos</title><content type='html'>&lt;div align="left"&gt;Muchas veces nos encontramos con una base de datos con gran cantidad de tablas, claves primarias y columnas. Y algunas veces, nos gustaría tener un pequeño inventario de todos estos datos, para poder sacar, de un vistazo, una visión global de la base de datos con la que trabajamos.&lt;br /&gt;&lt;br /&gt;Hacer un documentador es muy fácil si sabemos lo que queremos buscar y cómo podemos obtenerlo.&lt;br /&gt;&lt;br /&gt;Primero vamos a definir qué queremos buscar. Supongamos que queremos hacer un inventario con las tablas de nuestra base de datos, sus columnas y los procedimientos almacenados que están asociados.&lt;br /&gt;&lt;br /&gt;¿Cómo obtenerlos?&lt;br /&gt;Vamos a buscar en 2 vistas que nos ofrece SQL Server: Sys.Objects y Information_Schema (con sus variantes).&lt;/div&gt;&lt;div align="left"&gt;&lt;br /&gt;&lt;strong&gt;Paso 1&lt;/strong&gt;&lt;br /&gt;Obtener las tablas de la base de datos. Lo haremos con la query:&lt;/div&gt;&lt;div align="left"&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;Select * from sys.objects where [Type]='U'&lt;/span&gt;&lt;/div&gt;&lt;div align="left"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;Para sacar otros elementos, basta con cambiar el tipo o no poner clausula Where, para obtener todas las filas.&lt;br /&gt;Algunos tipos son:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;F          FOREIGN_KEY_CONSTRAINT&lt;br /&gt;FN       SQL_SCALAR_FUNCTION&lt;br /&gt;IT        INTERNAL_TABLE&lt;br /&gt;P          SQL_STORED_PROCEDURE&lt;br /&gt;PK       PRIMARY_KEY_CONSTRAINT&lt;br /&gt;S          SYSTEM_TABLE&lt;br /&gt;SQ       SERVICE_QUEUE&lt;br /&gt;U         USER_TABLE&lt;br /&gt;UQ      UNIQUE_CONSTRAINT&lt;br /&gt;V         VIEW&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Paso 2&lt;/strong&gt;&lt;br /&gt;Vamos a buscar las columnas de la tabla en cuestión.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;Select *&lt;br /&gt;from Information_Schema.columns&lt;br /&gt;Where Table_Name = 'nombreTabla'&lt;br /&gt;And Table_Catalog = 'nombreBaseDeDatos'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con esta query sacamos toda la información relativa a las columnas de la tabla en cuestión, como el nombre, si puede o no ser NULL, tipo de datos que admite, etc.&lt;br /&gt;&lt;br /&gt;Ya tenemos toda la información relativa a las tablas y sus columnas. Ahora vamos a buscar información acerca de los procedimientos almacenados.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Paso 3&lt;/strong&gt;&lt;br /&gt;Obtener todos los procedimientos almacenados de la base de datos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;Select  * From   INFORMATION_SCHEMA.ROUTINES&lt;br /&gt;Where Routine_Type = 'Procedure'&lt;br /&gt;And Specific_Catalog = 'nombreBaseDeDatos'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con esto obtenemos el nombre, la definición del procedimiento, la fecha de creación y de modificación, entre otras cosas…&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Paso 4&lt;/strong&gt;&lt;br /&gt;Obtener los datos relativos a esos procedimientos almacenados. Usaremos la siguiente query para ello:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;select *&lt;br /&gt;From            INFORMATION_SCHEMA.ROUTINES           ISR&lt;br /&gt;Inner Join        INFORMATION_SCHEMA.PARAMETERS ISP&lt;br /&gt;On                      ISR.ROUTINE_NAME = ISP.SPECIFIC_NAME&lt;br /&gt;Where      &lt;br /&gt;      ISR.Routine_Type = 'Procedure'     &lt;br /&gt;And&lt;br /&gt;      ISR.Specific_catalog = 'nombreBaseDatos'&lt;br /&gt;And&lt;br /&gt;      ISR.Specific_Name = ‘nombreProcedimientoAlmacenado’&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esta query nos dará los parámetros de ese procedimiento almacenado, su tipo, su dirección, su nombre….&lt;br /&gt;&lt;br /&gt;Con estos simples pasos puedo ir sacando la estructura de mi base de datos. Tirando de esas queries, es posible que encontréis mucha más información que la que os muestro.&lt;br /&gt;&lt;br /&gt;Un saludo,&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-7515459301482671782?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/7515459301482671782/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=7515459301482671782' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7515459301482671782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7515459301482671782'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/documentando-nuestra-base-de-datos.html' title='Documentando nuestra base de datos'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-2621135971772006557</id><published>2007-05-30T15:23:00.000+02:00</published><updated>2007-05-30T15:47:14.297+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Report'/><title type='text'>Buscando el Report ideal... (2)</title><content type='html'>&lt;p&gt;Cosas a tener en cuenta cuando damos formato a un report&lt;br /&gt;&lt;br /&gt;Aquí van unas guías para que no se olvide qué hay que comprobar a la hora de dar formato. Es una checklist para confirmar que no nos dejamos nada cuando demos formato.&lt;br /&gt;&lt;br /&gt;- ¿Está el Report dividido en Header, Body y Footer? Si falta algún elemento, justificarlo.&lt;br /&gt;- ¿Está configuarado el ancho y alto de la página, así como los márgenes? Si no, al exportar no va a funcionar.&lt;br /&gt;- ¿Está el mapa del report bien construido, aunque no se muestre en pantalla? Tened en cuenta que, por defecto, al exportarlo a Excel, se exporta el mapa en una hoja aparte. Cuidado que lo que se muestra en el mapa sea significativo (por ejemplo, que no se vean los identificadores que hemos usado para ordenar)&lt;br /&gt;- Comprobar las columnas, que cada celda mantiene la anchura y altura a lo largo de los reports. Esto es, la columna “Nombre de cliente” deberá tener el mismo ancho y alto en todos los reports que hagamos.&lt;br /&gt;- Las imágenes a mostrar son coherentes.&lt;br /&gt;- Si se usa algún elemento para listas (“-“, “*”,…), nos aseguramos que se usa siempre y que se usa siempre el mismo.&lt;br /&gt;- Cada campo se corresponde con su cabecera de columna… que el copy-paste es peligroso…&lt;br /&gt;- Exportar a los formatos a los que el usuario pueda exportar y comprobar que se exporta bien (que no quedan columnas separadas en una sola hoja, que los símbolos que he usado se exportan bien, etc…)&lt;br /&gt;- Hacer pruebas con campos largos y comprobar que están alineados tanto en horizontal como en vertical como deseamos.&lt;br /&gt;- Si usamos drilling-down, expandir todos los campos posibles para ver como queda el report en el peor de los casos.&lt;br /&gt;- Hacer una batería de pruebas en el servidor de reporting, puesto que hay cosas que con la preview del diseñador no se pueden comprobar, como son los tooltips y el javascript que hayamos podido meter.&lt;br /&gt;- Comprobar los links, que van donde van y que encuentran las páginas o reports como esperan.&lt;br /&gt;&lt;br /&gt;Una gran idea sería hacer un report con todo lo que queremos y definir una serie de pautas para los siguientes (definir pautas no significa copy-paste). Podríamos definir:&lt;br /&gt;- El ancho que va a tener cada columna&lt;br /&gt;- Los bordes de las celdas que se van a mostrar&lt;br /&gt;- Que celdas tienen tooltip y cuál es el formato&lt;br /&gt;- Como se va a definir la navegación, si la hay (va a ser sobre toda la fila o va a haber una celda concreta para navegar)&lt;br /&gt;- La cabecera del report y el pie de pagina&lt;br /&gt;- Los tipos de letra de cada celda, alineación vertical y horizontal y posibles efectos.&lt;br /&gt;- Preparar unos datos de reporting que nos permitan “someter” a nuestros reports a las más descabelladas situaciones (esas que son imposibles de darse, pero que el cliente siempre lo logra…, y menos mal que muchos ni saben de informática)&lt;br /&gt;&lt;br /&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/35785998-2621135971772006557?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/2621135971772006557/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=2621135971772006557' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2621135971772006557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2621135971772006557'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/buscando-el-report-ideal-2.html' title='Buscando el Report ideal... (2)'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-797256834205471637</id><published>2007-05-29T15:38:00.000+02:00</published><updated>2007-05-29T15:42:11.587+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reporting Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Report'/><title type='text'>Buscando el report ideal...</title><content type='html'>&lt;p&gt;¿Qué características debe tener el report ideal? Cuantas más y mejores herramientas tenemos, tenemos tentaciones de dejarnos llevar por aburridos wizards o complicar en exceso los reports.&lt;br /&gt;&lt;br /&gt;Mi “mini-guia” del report ideal se basaría en los siguientes puntos:&lt;br /&gt;1. Un report es específico: la información que se muestra es concreta. No debería tener información que no aporte valor al usuario. Tener un mega-report no es una buena solución, aún cuando el usuario crea que sí. La información debe estar estructurada.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;2. Un report no debe reflejar TODO el estado de la empresa: hacer un report que no filtra por nada lo que viene de la base de datos, no tiene sentido. Un report que hoy me parece adecuado aunque no filtre por fechas, dentro de 10 años moverá tanta información que no será válido. Vale que en 10 años ese report habrá sido sustituido “n” veces, pero eso no es excusa…&lt;/p&gt;&lt;p&gt;&lt;br /&gt;3. Un report debe ser agradable al usuario. Ojo con los scrolls (el scroll horizontal es bastante incómodo para el usuario). Ojo con el formato del texto y ojo con el formato de la tabla.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;4. Un report debe permitir cierta interactividad con el usuario. Incluir una cierta dosis de navegación permite al usuario organizar y leer más fácilmente la información.&lt;/p&gt;&lt;p&gt;5. Un report no es infinito. Si quiero mostrar demasiados datos, es posible que tenga que incluir un subreport o un link a otro report.&lt;/p&gt;&lt;p&gt;6. Lo que se muestra no tiene por qué ser lo único que hay. Incluir tooltips para mostrar más información poede ser una buena idea, en su justa medida. Meter tooltips en todos lados equivoca al usuario y le acaba haciendo pensar que tiene que ponerse encima de todos los campos para ver más datos.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;7. El usuario debe saber qué va a pasar cuando haga clic en el report. Meter links a otros sitios sin ton ni son, puede equivocar al usuario, a menos que esté muy claro lo que hace.&lt;br /&gt;Javascript, sí, pero sólo si ayuda. Mostrar un pop-up con información extendida, puede ser una buena idea. Mostrar pop-ups en todos lados, no es buena práctica.&lt;/p&gt;&lt;p&gt;8. El report se genera rápido (si es posible). Para ello, debo:&lt;/p&gt;&lt;p&gt;- Delimitar la información a mostrar&lt;br /&gt;- Mejorar las queries que recogen los datos&lt;br /&gt;- Minimizar al máximo el peso del report (imágenes, las justas)&lt;/p&gt;&lt;p&gt;9. La imagen del report es la imagen de la empresa. Lo cual requiere que TODOS los reports matengan unos criterios de formatos. Misma letra, mismo tamaño, mismas imágenes, mismo estilo en header y footer…&lt;/p&gt;&lt;p&gt;10.Un report no es una aplicación web. Si se da demasiada interactividad a un report, de la sensación de que es una página web más y eso no debería ser así. Si es así, es posible que no necesitemos Reporting Services, sino una página ASP.NET.&lt;br /&gt;&lt;br /&gt;Un saludo &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;PD: Pido disculpas a David por usar tantas veces el término "report"... jaja&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-797256834205471637?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/797256834205471637/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=797256834205471637' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/797256834205471637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/797256834205471637'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/buscando-el-report-ideal.html' title='Buscando el report ideal...'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-5173449408630445869</id><published>2007-05-25T09:45:00.001+02:00</published><updated>2007-05-25T10:16:44.404+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Debug'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>XSLT Debugging?????? Si, y muy fácil</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Si hace unos años me hablan de la posibilidad de debuggar .NET al nivel que se debuga ahora con Visual Studio, seguramente preguntaría "¿Qué es eso de .NET?".&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Pues bien, en un momento en el que XML parece que se convierte en un standard de intercambio de información y en el que aparecen montones de tecnologías que, bien lo mejoran, bien lo complementan, bien hacen uso de él, voy poco a poco descubriendo herramientas que facilitan la vida.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Si hace poco descubrí la potencia de XSLT, ahora Visual Studio me sorprende con un debugger de XSLT.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;¿¿¿Sorprendido??? Yo bastante... :-)&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Primero, buscar el botón de XSLT Debugging.&lt;br /&gt;En el menú: Tools--&gt;Customize--&gt;Pestaña de Commands. Busco la categoría de XML. Me aparecerán 4 posibles botones. Arrastro &lt;a href="http://bp2.blogger.com/_o4DgEEflDiw/RlaapfqxSlI/AAAAAAAAAAU/-_ov3gvIggo/s1600-h/XSLT_Debugger_01.GIF"&gt;&lt;img id="BLOGGER_PHOTO_ID_5068408468318276178" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand" alt="" src="http://bp2.blogger.com/_o4DgEEflDiw/RlaapfqxSlI/AAAAAAAAAAU/-_ov3gvIggo/s200/XSLT_Debugger_01.GIF" border="0" /&gt;&lt;/a&gt;el “Debug XSLT” a la barra de herramienta. También vamos a arrastrar el “Show XSLT Output”, porque vamos a ver un pequeño “truco” al final.&lt;br /&gt;&lt;br /&gt;Bien, ahora necesitamos un XSLT, lo abrimos. Doy al botón de debuggar XSLT y, si no tengo definido ningún XML que transformar, me pedirá que lo especifique. Lo selecciono marcando la ruta y ¡empieza la fiesta!&lt;br /&gt;&lt;br /&gt;Se muestran dos ventanas: el XSLT y el XSLT output. El XSLT (poned puntos de interrupción, si no no vamos a ver nada… :-) ) aparecerá con la siguiente instrucción a debuggar.&lt;br /&gt;&lt;br /&gt;Con F10 voy poco a poco navegando por las instrucciones y, a medida que los elementos HTML se van completando, irán apareciendo en la ventana de la derecha.&lt;br /&gt;Por completar me refiero a, por ejemplo, tablas completas (no filas o columnas), labels, etc…&lt;br /&gt;&lt;a href="http://bp0.blogger.com/_o4DgEEflDiw/Rlaaz_qxSmI/AAAAAAAAAAc/vlrmqq_m9Us/s1600-h/XSLT_Debugger_02.GIF"&gt;&lt;img id="BLOGGER_PHOTO_ID_5068408648706902626" style="FLOAT: right; MARGIN: 0px 0px 10px 10px; WIDTH: 316px; CURSOR: hand; HEIGHT: 237px" height="215" alt="" src="http://bp0.blogger.com/_o4DgEEflDiw/Rlaaz_qxSmI/AAAAAAAAAAc/vlrmqq_m9Us/s200/XSLT_Debugger_02.GIF" width="289" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Si tenemos presente el XML y predecimos el flujo que debería seguir a lo largo de los Xsl:Otherwise y Xsl:If, podemos comprobar que el XSLT funciona como debe.&lt;br /&gt;&lt;br /&gt;Mmmm ¿¿¿pero podría usar también la ventana de Watch para ver en que estado están las variables??? La respuesta es SÍ!!!&lt;br /&gt;Pero no es tan facil como arrastrar la variable a la tabla. Ahora la ventana Watch entiende XPath. Es decir, si hay una tag en el XML que es Cliente/Nombre y quiero ver su valor, lo que debo hacer para comprobar que valor tiene ahora mismo esa variable es escribir en la ventana de Watch Cliente/Nombre/text()… XPath puro y duro…&lt;br /&gt;&lt;br /&gt;Y también puedo comparar, buscar atributos…. Todo lo que XPath permite para consultar sus nodos. Ojo porque la ventana Watch no es una ventana para hacer queries contra el XML… porque analiza el XML según sonde está la ejecución del XSLT. Esto es, si estoy navegando por Empleados/Empleado, si accedo al nombre, será por medio de ./Nombre.&lt;br /&gt;&lt;br /&gt;Y a partir de aquí, imaginación…&lt;br /&gt;&lt;br /&gt;Un regalito, el botón de XSLT Output que hemos añadido antes abrirá la salida que produce el XSLT sin debuggar. La buena noticia, que vemos a la vez el XSLT y el resultado que produce. ¿La buenísima? Que lo que cambiemos en el XSLT se traduce directamente en el output.&lt;br /&gt;&lt;br /&gt;Si es que programar está chupado….&lt;br /&gt;Más fuentes:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms255602(VS.80).aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms255602(VS.80).aspx&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.google.com"&gt;http://www.google.com&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-5173449408630445869?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/5173449408630445869/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=5173449408630445869' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5173449408630445869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/5173449408630445869'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/xslt-debugging-si-y-muy-fcil.html' title='XSLT Debugging?????? Si, y muy fácil'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_o4DgEEflDiw/RlaapfqxSlI/AAAAAAAAAAU/-_ov3gvIggo/s72-c/XSLT_Debugger_01.GIF' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-3271609263146389409</id><published>2007-05-24T17:13:00.000+02:00</published><updated>2007-05-24T17:33:16.378+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Links para Patterns</title><content type='html'>Hacer lo que otros ya han hecho es lograr despues del tiempo que ellos estuvieron trabajando en ello, llegar al mismo sitio que ellos llegaron (si no un poco menos lejos).&lt;br /&gt;&lt;br /&gt;Es así, siempre ha sido y siempre será. Para eso nacen los patterns. "Cosas" que están hechas, probadas, requeteprobadas y documentadas. No se nada de patterns (nada de nada). Lo poco que he hecho en ese campo ha sido usar un par de patterns, pero no considero que sepa nada al respecto. No asbría explicarlo.&lt;br /&gt;Mi amigo Jaime uso un día un Singleton, pero de verdad... sabiendo porqué y cómo. Así da gusto... :-)&lt;br /&gt;&lt;br /&gt;Por ello, y a modo de referencia y compendio, ahí van una serie de links de la gente que SÍ sabe de esto:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.programmersheaven.com/2/Design-Patterns-in-VB"&gt;About the Design Patterns in VB.NET&lt;/a&gt; (una buena guia de iniciación, con un poco de todo)&lt;br /&gt;&lt;a href="http://www.codeproject.com/cs/design/statepatterncsharp.asp"&gt;C# - State Pattern Example&lt;/a&gt; (un pattern para manejo de estado, en 1.1)&lt;br /&gt;&lt;a href="http://mudabone.com/aietc/?page_id=335"&gt;Model-View-Controller in ASP.NET 2.0&lt;/a&gt; (pattern para simplificar la capa UI)&lt;br /&gt;&lt;br /&gt;Un saludo&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-3271609263146389409?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/3271609263146389409/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=3271609263146389409' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3271609263146389409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3271609263146389409'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/links-para-patterns.html' title='Links para Patterns'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-834464758826414374</id><published>2007-05-24T16:26:00.000+02:00</published><updated>2007-05-24T16:31:59.823+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Diseño de aplicacion multi-capa (para arquitectos... y para todos los que teclean)</title><content type='html'>Buenas,&lt;br /&gt;&lt;br /&gt;Este artículo &lt;a href="http://www.codeproject.com/gen/design/TieredDesign.asp"&gt;Introduction to Object-Oriented Tiered Application Design&lt;/a&gt;, es un gran redumen de qué es y como funciona el N-Tier design, incluyendo algunas consideraciones de validación y seguridad que no están nada mal.&lt;br /&gt;&lt;br /&gt;Un artículo que todos deberíamos leer para entender porqué separamos en capas la aplicación... Entender lo que hacemos hace que seamos capaces de entender los retos que plantea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-834464758826414374?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/834464758826414374/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=834464758826414374' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/834464758826414374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/834464758826414374'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/diseo-de-aplicacion-multi-capa-para.html' title='Diseño de aplicacion multi-capa (para arquitectos... y para todos los que teclean)'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-3802593272729247719</id><published>2007-05-24T16:21:00.000+02:00</published><updated>2007-05-24T16:31:36.547+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'></title><content type='html'>Vamos a dar una vuelta de tuerca más al control XML de ASP.NET.&lt;br /&gt;Ya hemos visto &lt;a href="http://aspnetmadgas.blogspot.com/2007/05/xslt-y-el-control-xml-de-aspnet.html"&gt;como configurar un control XML&lt;/a&gt;. Ahora vamos a darle un poco de dinamismo.&lt;br /&gt;Vamos a mostrar datos sacado de una base de datos.&lt;br /&gt;Tenemos una tabla de empleados. Así mismo, como quiero que varios clientes puedan consultar la lista, voy a proporcionarles un Web Service que va a dar un XML con la lista de empleados. Así, cada uno podrá customizar como mostrar unos datos.&lt;br /&gt;Esto es, vamos a proporcionar un Web Service que va a proporcionar a lo usuarios un XML con la lista. Luego, cada usuario tendrá un XSLT que mostrará lo que le interese, y como le interese.&lt;br /&gt;&lt;br /&gt;Paso 1: La query&lt;br /&gt;&lt;br /&gt;Mmmm queremos una query que nos devuelva un XML. En esta &lt;a href="http://blah.winsmarts.com/2007-2-Bak2Basics__Learn_T-SQL_-_FOR_XML.aspx"&gt;web&lt;/a&gt; tenéis varias formas de lograr ese output. Nos quedamos con la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;SELECT (CAST((    SELECT '&lt;empleados&gt;') +&lt;br /&gt;(                       SELECT      EmpleadoId,&lt;br /&gt;                              RTRIM([EmpleadoNm])     AS Nombre&lt;br /&gt;                              ,RTRIM([EmpleadoSNm])AS Apellidos&lt;br /&gt;                              ,RTRIM([EmpleadoAge])   AS Edad&lt;br /&gt;                              ,RTRIM([EmpleadoSabiduria])AS Sabiduria&lt;br /&gt;                              FROM [TestingDB].[dbo].[Empleados]&lt;br /&gt;                              FOR XML PATH('Empleado')) +&lt;br /&gt;                        (SELECT '&lt;/empleados&gt;')&lt;br /&gt;            AS XML))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bien, ya tenemos la lista de empleados, cada uno de ellos con el tag Empleado.&lt;br /&gt;&lt;br /&gt;Ahora, a por el web service. Vamos a hacer que nos devuelva un XmlDocument (System.Xml). Esto permitirá al cliente manipularlo antes de darlo a la capa de presentación.&lt;br /&gt;&lt;br /&gt;El Web Service sería así:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;[WebMethod]&lt;br /&gt;    public XmlDocument GetEmpleados()&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        XmlDocument doc = new XmlDocument();&lt;br /&gt;&lt;br /&gt;        SqlConnection connection = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=TestingDB;Integrated Security=SSPI;");&lt;br /&gt;&lt;br /&gt;        SqlCommand command = new SqlCommand();&lt;br /&gt;        command.CommandText = "GetEmpleados";&lt;br /&gt;        command.CommandType = System.Data.CommandType.StoredProcedure;&lt;br /&gt;        command.Connection = connection;&lt;br /&gt;        connection.Open();&lt;br /&gt;&lt;br /&gt;        XmlReader reader = command.ExecuteXmlReader();&lt;br /&gt;&lt;br /&gt;        while (reader.Read())&lt;br /&gt;        {&lt;br /&gt;            doc.InnerXml = reader.ReadOuterXml();&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;        reader.Close();&lt;br /&gt;        connection.Close();&lt;br /&gt;        return doc;&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ahora, ¡a consumir el web service!&lt;br /&gt;&lt;br /&gt;Creamos un site y añadimos la referencia web. Añadimos un control XML, solo con ID y Runat=”Server”, nada más.&lt;br /&gt;Vamos a usar un fichero cualquiera de transformación.&lt;br /&gt;En la página, vamos a recogerlo con forma de XmlNode.&lt;br /&gt;&lt;br /&gt;El codigo en el Load, sería:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;     EmpleadosWS.Service servicioEmpleados = new EmpleadosWS.Service();&lt;br /&gt;     XmlNode node = (XmlNode )servicioEmpleados.GetEmpleados();&lt;br /&gt;     xmlViewer.DocumentContent = node.OuterXml;&lt;br /&gt;     xmlViewer.TransformSource = "~/App_Data/Transformador.xslt";&lt;br /&gt;     xmlViewer.DataBind();&lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No olvideis el DataBind!!!!!&lt;br /&gt;&lt;br /&gt;Un saludo&lt;br /&gt;&lt;br /&gt;Nota: es muy posible que se pueda hacer más optimizado... sobre todo la query. Cualquiera que quiera sugerir como hacer o mejorarlo, por favor, hagálo :-) .... y gracias&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-3802593272729247719?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/3802593272729247719/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=3802593272729247719' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3802593272729247719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/3802593272729247719'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/vamos-dar-una-vuelta-de-tuerca-ms-al.html' title=''/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-7024684681950018630</id><published>2007-05-24T13:24:00.000+02:00</published><updated>2007-05-24T15:05:55.589+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>Object Oriented Programming con Javascript</title><content type='html'>"Javascript es un lenguaje de niños", "Con javascript no se puede hacer casi nada" .... ¿Cuantas veces hemos dicho u oido esto?&lt;br /&gt;&lt;br /&gt;Yo mismo lo encontraba (aún hoy lo encuentro, porque no se usarlo bien :-( ) tedioso, complicado e inmanejable... Lo que hace el no saber. No obstante, usarlo bien abre muchas posibilidades (usarlo mal hará que acabemos con un proyecto en el que cada fallo implique horas y horas de debugging).&lt;br /&gt;&lt;br /&gt;Para usarlo bien, he aqui una serie de guias al respecto:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/05/javascript/default.aspx"&gt;Create Advanced Web Applications With Object-Oriented Techniques&lt;/a&gt;&lt;br /&gt;&lt;a href="http://archive.devx.com/dhtml/articles/td041801/td041801-1.asp"&gt;Ejemplo de menú usando OOP javascript&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Un saludo, espero que os guste&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-7024684681950018630?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/7024684681950018630/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=7024684681950018630' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7024684681950018630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/7024684681950018630'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/object-oriented-programming-con.html' title='Object Oriented Programming con Javascript'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-727033454795926474</id><published>2007-05-24T13:11:00.000+02:00</published><updated>2007-05-24T15:05:30.382+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><title type='text'>FindAll de Generics</title><content type='html'>Buenas a todos. Una de las ventajas de las listas, son la posibilidad de obtener otras listas con los datos filtrados de una primera.&lt;br /&gt;¿Cómo lo haríamos? Supongamos que tenemos una lista de enteros y que queremos sacar dos listas, una con los pares y otra con los impares. El codigo sería el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace Pruebas_Lenguaje_C_Sharp&lt;br /&gt;{&lt;br /&gt;public class Find_All_Generics&lt;br /&gt;{&lt;br /&gt;public Find_All_Generics(List&lt;int&gt; enteros)&lt;br /&gt;{&lt;br /&gt;if (enteros != null)&lt;br /&gt;__enteros = enteros;&lt;br /&gt;else&lt;br /&gt;throw new Exception("List passed cannot be null");&lt;br /&gt;}&lt;br /&gt;private List&lt;int&gt; __enteros;&lt;br /&gt;&lt;br /&gt;public List&lt;int&gt; Enteros&lt;br /&gt;{&lt;br /&gt;get&lt;br /&gt;{&lt;br /&gt;if (__enteros == null)&lt;br /&gt;__enteros = new List&lt;int&gt;();&lt;br /&gt;return __enteros;&lt;br /&gt;}&lt;br /&gt;set&lt;br /&gt;{&lt;br /&gt;__enteros = value;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;public List&lt;int&gt; GetPares()&lt;br /&gt;{&lt;br /&gt;return Enteros.FindAll(FindPares);&lt;br /&gt;}&lt;br /&gt;public List&lt;int&gt; GetImpares()&lt;br /&gt;{&lt;br /&gt;return Enteros.FindAll(FindImpares);&lt;br /&gt;}&lt;br /&gt;// Esta funcion debra devolver true para aquellos elementos que queramos filtrar.&lt;br /&gt;// El metodo FindAll ejecutara este metodo por cada elemento de la lista y, si el&lt;br /&gt;// resultado es True, lo añadirá al resultado&lt;br /&gt;bool FindPares(int entero)&lt;br /&gt;{&lt;br /&gt;return (entero % 2 == 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool FindImpares(int entero)&lt;br /&gt;{&lt;br /&gt;return (entero % 2 != 0);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;En el Main, ponemos:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;List&lt;int&gt; enteros = new List&lt;int&gt;();&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; 10; i++)&lt;br /&gt;enteros.Add(i);&lt;br /&gt;&lt;br /&gt;Find_All_Generics exampleList = new Find_All_Generics(enteros);&lt;br /&gt;&lt;br /&gt;Console.WriteLine("Pares: ");&lt;br /&gt;foreach (int i in exampleList.GetPares())&lt;br /&gt;Console.WriteLine(i);&lt;br /&gt;Console.WriteLine("Impares: ");&lt;br /&gt;foreach (int i in exampleList.GetImpares())&lt;br /&gt;Console.WriteLine(i);&lt;br /&gt;Console.ReadKey();&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Y comprobamos el resultado.&lt;br /&gt;&lt;br /&gt;Esto es muy útil para realizar filtros sobre las listas. Por ejemplo,&lt;br /&gt;- De una lista de empleados, puedo querer sacar una lista de los que son mayores de 40 años.&lt;br /&gt;- De una lista de eventos deportivos, puedo querer filtrar los que son el domingo que viene&lt;br /&gt;- etc...&lt;br /&gt;&lt;br /&gt;Muchísimas gracias a Gloria por enseñarme el "fántastico mundo del FindAll" :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-727033454795926474?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/727033454795926474/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=727033454795926474' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/727033454795926474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/727033454795926474'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/findall-de-generics.html' title='FindAll de Generics'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-8151264343822260008</id><published>2007-05-24T13:02:00.000+02:00</published><updated>2007-05-24T15:06:16.216+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>XSLT avanzado</title><content type='html'>Ojo al articulo linkado &lt;a href="http://www.15seconds.com/issue/010921.htm"&gt;aqui&lt;/a&gt;.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;El articulo va de como hacer un arbol para navegar por los elementos de un XML basado en XSLT y algo de Javascript. Mi consejo es que os bajeis el ZIP de ejemplo y le echeis un vistazo.&lt;br /&gt;&lt;br /&gt;Os va a gustar :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-8151264343822260008?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/8151264343822260008/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=8151264343822260008' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8151264343822260008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8151264343822260008'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/xslt-avanzado.html' title='XSLT avanzado'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-8075770266805567729</id><published>2007-05-23T16:07:00.001+02:00</published><updated>2007-05-24T15:06:16.216+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>XSLT y el control XML de ASP.NET</title><content type='html'>Uno de los controles menos ducumentados de ASP.NET en su version 2.0 es el XML Control. Tampoco hay mucho que documentar, pues basta con configurar cual es el origen de datos (el XML) y quien lo va a pintar (el XSLT). Con esto conseguimos varias cosas:&lt;br /&gt;1.       Independizamos cada componente de los demás-     XML solo sabe de datos, no tiene ni idea de cómo se pintan en pantalla&lt;br /&gt;-         XSLT solo sabe como pintarlos. No sabe cuales son. Sólo sabe que espera recibir unos campos, sean los que sean.&lt;br /&gt;-         La pagina Web con su control XML no sabe ni que va a pintar ni como. Solo sabe en que posición de la página van.&lt;br /&gt;2.      Logramos que cambios en el futuro afecten a una capa solamente, no a todas.&lt;br /&gt;&lt;br /&gt;Para aprender a manejar XSLT, conviene ver los siguientes links:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/msdnmag/issues/02/03/xml/"&gt;Meter Javascript y código .NET en XSLT&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.w3schools.com/xsl/"&gt;Tutorial de iniciación a XSLT&lt;/a&gt;&lt;br /&gt;&lt;a href="http://incrementaldevelopment.com/xsltrick/"&gt;Trucos y cosas curiosas de XSLT&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-8075770266805567729?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/8075770266805567729/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=8075770266805567729' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8075770266805567729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/8075770266805567729'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/xslt-y-el-control-xml-de-aspnet.html' title='XSLT y el control XML de ASP.NET'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-2039782008547638120</id><published>2007-05-23T15:24:00.000+02:00</published><updated>2007-05-23T16:06:38.047+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>XQuery-SQL Server 2005 - La guia</title><content type='html'>&lt;span style="font-family:arial;font-size:85%;"&gt;Hace tiempo que empecé a escribir sobre XQuery y apunté unos cuantos links útiles. Ahora vamos a dar una vuelta de tuerca y vamos a poner varios ejemplos.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Para ello vamos a usar un XML que tenga, más o menos variedad de cosillas: campos que se repiten, campos que no, elementos simples, complejos... para aplicar lo que aprendamos.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;El XML podría ser el que sigue:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_o4DgEEflDiw/RlRKNvqxSkI/AAAAAAAAAAM/VLZvVyHm-_o/s1600-h/Encuesta.GIF"&gt;&lt;img id="BLOGGER_PHOTO_ID_5067757080693262914" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 234px; CURSOR: hand; HEIGHT: 320px" height="320" alt="" src="http://bp1.blogger.com/_o4DgEEflDiw/RlRKNvqxSkI/AAAAAAAAAAM/VLZvVyHm-_o/s320/Encuesta.GIF" width="337" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;encuesta&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Vale, ya tenemos el XML, vamos a empezar a hacer consultas basicas:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Antes de nada, vamos a ver la estructura que tienen las queries.&lt;br /&gt;&lt;br /&gt;for $A in /Encuesta/Contenido/Pregunta&lt;br /&gt;where $A/Respuesta = “SI”&lt;br /&gt;return $A/Texto&lt;br /&gt;&lt;br /&gt;Esta query nos va a buscar dentro de todas la preguntas. Va a filtrar las que cumplan que la respuesta es si, y nos va a devolver el enunciado (texto) de la pregunta&lt;br /&gt;&lt;br /&gt;Abrimos una nueva Query en SQL Server y escribimos:&lt;br /&gt;&lt;br /&gt;select @xmlText.query('for $A in /Encuesta/Contenido/Pregunta&lt;br /&gt;where $A/Respuesta = ''SI''&lt;br /&gt;return $A/Texto&lt;br /&gt;')&lt;br /&gt;&lt;br /&gt;Nos devolverá:&lt;br /&gt;&lt;texto&gt;¿Le gusta el cine?&lt;/texto&gt;&lt;br /&gt;&lt;texto&gt;¿Le gusta el futbol?&lt;/texto&gt;&lt;br /&gt;&lt;br /&gt;Vamos a refinar un poco… Ahora solo queremos que nos devuelva el contenido, sin tags xml. La query seria:&lt;br /&gt;&lt;br /&gt;select @xmlText.query('for $A in /Encuesta/Contenido/Pregunta&lt;br /&gt;where $A/Respuesta = ''SI''&lt;br /&gt;return $A/Texto&lt;br /&gt;').value('(//Texto/text())[1]','VARCHAR(MAX)')&lt;br /&gt;&lt;br /&gt;Al ejecutarlo, hay un problema: solo nos devuelve el primero de los campos… Esto nos vale SOLO cuando sabemos que sólo hay un campo. Por ejemplo, en nuestro caso sería una busqueda del nombre de un encuestado.&lt;br /&gt;&lt;br /&gt;Vamos a solucionar el problemilla… Vamos a hacer dos técnicas:&lt;br /&gt;Mostrar los dos en el mismo campo: Para ello vamos a hacer uso de una cuncion de XQuery: concat. Vamos a concatenar todas las preguntas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select @xmlText.query('for $A in /Encuesta/Contenido/Pregunta&lt;br /&gt;where $A/Respuesta = ''SI''&lt;br /&gt;return concat($A/Texto[1]," - ")&lt;br /&gt;')&lt;br /&gt;&lt;br /&gt;Mejor, ahora nos devuelve las preguntas concatenadas…&lt;br /&gt;&lt;br /&gt;Mostrar una fila por cada coincidencia: es posible que queramos mostrar una fila por pregunta, para ello haremos uso de la siguiente query. Necesitamos que el XML esté en una tabla, porque necesitamos hacer un CROSS. La query sería:&lt;br /&gt;&lt;br /&gt;SELECT&lt;br /&gt;cast(R.EncuestaDetails.query('.')&lt;br /&gt;.value('(/Texto)[1]','VARCHAR(MAX)')&lt;br /&gt;AS VARCHAR(100))&lt;br /&gt;AS ClienteNm&lt;br /&gt;&lt;br /&gt;FROM&lt;br /&gt;[Encuesta] C&lt;br /&gt;CROSS APPLY&lt;br /&gt;C.[EncuestaXML].nodes('/Encuesta/Contenido/Pregunta)&lt;br /&gt;AS R(EncuestaDetails)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;Esto nos devolvería todas las preguntas (una por fila) que haya en los XML de la tabla.&lt;br /&gt;&lt;br /&gt;Genial!!!! No?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-2039782008547638120?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/2039782008547638120/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=2039782008547638120' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2039782008547638120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/2039782008547638120'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2007/05/xquery-sql-server-2005-la-guia.html' title='XQuery-SQL Server 2005 - La guia'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_o4DgEEflDiw/RlRKNvqxSkI/AAAAAAAAAAM/VLZvVyHm-_o/s72-c/Encuesta.GIF' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116290479068152744</id><published>2006-11-07T13:58:00.000+01:00</published><updated>2007-05-24T15:05:00.027+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SPS 2007'/><title type='text'>Sharepoint 2007</title><content type='html'>&lt;span style="font-family:arial;"&gt;La llegada inminente de una herramienta del poder que, aparentemente, tendrá Sharepoint 2007 no debría dejar indiferente al mundo de los programadores y desarrolladores y arquitectos y...&lt;br /&gt;Como consejo, apuntarse a los cursos gratuitos de &lt;/span&gt;&lt;a href="https://www.microsoftelearning.com/default.aspx"&gt;&lt;span style="font-family:arial;"&gt;e-learning&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:arial;"&gt; de Microsoft en este sentido, que nos darán una imagen general de que vamos a poder hacer (clinic 5045) y, por supuesto, enredar por los blogs de los expertos:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sharepointblogs.com/dustin/articles/5235.aspx"&gt;Caracteristicas de SPS 2007&lt;/a&gt;&lt;br /&gt;&lt;a href="http://channel9.msdn.com"&gt;Videos varios sobre la nueva tecnología&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116290479068152744?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116290479068152744/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116290479068152744' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116290479068152744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116290479068152744'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/sharepoint-2007.html' title='Sharepoint 2007'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116255911613472650</id><published>2006-11-03T14:03:00.000+01:00</published><updated>2007-05-24T15:06:33.775+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seguridad'/><title type='text'>Gran documento sobre modelado de amenazas</title><content type='html'>En las aplicaciones actuales, donde Internet empieza a ser un hábito cada vez más habitual, es necesario hacer un estudio muy serio de las aplicaciones que construimos.&lt;br /&gt;Para ayudarnos (no para darnos las respuestas a todas nuestras dudas), aquí va este &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/11/ThreatModeling/Default.aspx?loc=es"&gt;documento&lt;/a&gt; que nos ayudará.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116255911613472650?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116255911613472650/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116255911613472650' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116255911613472650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116255911613472650'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/gran-documento-sobre-modelado-de.html' title='Gran documento sobre modelado de amenazas'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116255191308243082</id><published>2006-11-03T11:44:00.000+01:00</published><updated>2007-05-24T15:06:49.691+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>Convertir ficheros de formato</title><content type='html'>&lt;span style="font-family:arial;"&gt;Aqui mando un &lt;/span&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/dh0797c4.aspx"&gt;&lt;span style="font-family:arial;"&gt;link&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:arial;"&gt; con un metodo para convertir ficheros de formato en .NET 2.0.&lt;br /&gt;Podremos cambiar de UTF-8 a 16, etc..&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116255191308243082?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116255191308243082/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116255191308243082' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116255191308243082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116255191308243082'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/convertir-ficheros-de-formato.html' title='Convertir ficheros de formato'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116248258921224104</id><published>2006-11-02T16:28:00.000+01:00</published><updated>2007-05-24T15:07:04.897+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>XQuery</title><content type='html'>Que es evidante que Sql Server 2005 representa una gran evolucion en lo que entendemos acerca de las bases de datos es evidente.&lt;br /&gt;Una de las facetas que mas rendimiento nos aporta es el tratamiento de XML. Poder buscar dentro de los nodos de un XML es algo bastante útil, sobre todo ahora que la evolución de la información tiende a XML.&lt;br /&gt;Para buscar datos, basta con usar XQuery (un formato de búsquedas similar a lo que ofrece SQL para tablas). No voy a dar ninguna lección, pero voy a incluir unas referencias de gente que sabe bastante de esto:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/es-es/library/ms189075.aspx"&gt;http://msdn2.microsoft.com/es-es/library/ms189075.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Información de Microsoft:&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms345122.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms345122.aspx&lt;/a&gt;&lt;br /&gt;Tutorial de XQuery:&lt;br /&gt;&lt;a href="http://media.datadirect.com/download/docs/ddxquery/tutorial_query.html"&gt;http://media.datadirect.com/download/docs/ddxquery/tutorial_query.html&lt;/a&gt;&lt;br /&gt;Más XQuery, libro incluido:&lt;br /&gt;&lt;a href="http://www.datadirect.com/developer/xquery/xquerybook/index.ssp"&gt;http://www.datadirect.com/developer/xquery/xquerybook/index.ssp&lt;/a&gt;&lt;br /&gt;Genial tutorial. Muy recomendable, aunque igual muy básico:&lt;br /&gt;&lt;a href="http://www.developer.com/db/article.php/3565996"&gt;http://www.developer.com/db/article.php/3565996&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116248258921224104?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116248258921224104/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116248258921224104' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116248258921224104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116248258921224104'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/xquery.html' title='XQuery'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116248012319753763</id><published>2006-11-02T16:05:00.000+01:00</published><updated>2007-05-24T15:07:25.800+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>Comparar 2 XML en SQL Server 2005</title><content type='html'>&lt;span style="font-family:arial;"&gt;Ojo porque no se puede compara tan alegremente los XML como unos varchar o int en SQL Server 2005.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Por ello, hay que meterse en el CLR de SQL. Para solucionar este problema, mirad este link:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://pluralsight.com/blogs/dan/archive/2006/09/01/36829.aspx"&gt;&lt;span style="font-family:arial;"&gt;http://pluralsight.com/blogs/dan/archive/2006/09/01/36829.aspx&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116248012319753763?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116248012319753763/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116248012319753763' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116248012319753763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116248012319753763'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/comparar-2-xml-en-sql-server-2005.html' title='Comparar 2 XML en SQL Server 2005'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35785998.post-116247981240360692</id><published>2006-11-02T15:55:00.000+01:00</published><updated>2007-05-24T15:07:17.113+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2005'/><title type='text'>SQL Server 2005 no entiende UTF-8</title><content type='html'>&lt;span style="font-family:arial;"&gt;Haciendo una pruebas sobre almacenamiento y manejo de ficheros XML con el SQL Server 2005, me he encontrado con un problema, y es que SQL Server 2005 sólo maneja formato UTF-16.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;El problema es que, por ejemplo, un fichero Infopath tiene la cabecera:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Y al guardarlo falla, evidentemente.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Para solucionarlo, no nos queda otra que convertirlo de encoding. En .NET 2.0, tenemos métodos como Encoding.Convert(src,fnl,byte[]).&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Otra fuentes interesantes sobre el tema:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/es-es/library/ms187107.aspx"&gt;&lt;span style="font-family:arial;"&gt;http://msdn2.microsoft.com/es-es/library/ms187107.aspx&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://geekswithblogs.net/vkamat/archive/2006/01/20/66561.aspx"&gt;&lt;span style="font-family:arial;"&gt;http://geekswithblogs.net/vkamat/archive/2006/01/20/66561.aspx&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Error Text::: "XML parsing: line 1, character 38, unable to switch the encoding"&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35785998-116247981240360692?l=aspnetmadgas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aspnetmadgas.blogspot.com/feeds/116247981240360692/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35785998&amp;postID=116247981240360692' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116247981240360692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35785998/posts/default/116247981240360692'/><link rel='alternate' type='text/html' href='http://aspnetmadgas.blogspot.com/2006/11/sql-server-2005-no-entiende-utf-8.html' title='SQL Server 2005 no entiende UTF-8'/><author><name>Triki</name><uri>http://www.blogger.com/profile/17443067252781854949</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
