<?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-37408564</id><updated>2012-01-24T19:09:09.460Z</updated><category term='DTD'/><category term='dicom'/><category term='artículo'/><category term='Rijndael'/><category term='worklist'/><category term='boda'/><category term='cluster'/><category term='servidores'/><category term='seguridad'/><category term='máquina virtual'/><category term='Creative Commons'/><category term='AJAX'/><category term='skype'/><category term='pacs'/><category term='microblogging'/><category term='arquitectura'/><category term='c#'/><category term='imagen digital'/><category term='desfase'/><category term='concurso'/><category term='web 2.0'/><category term='NIS'/><category term='efeméride'/><category term='ris'/><category term='El Marco Lógico'/><category term='libro'/><category term='replicacion'/><category term='raid'/><category term='itextsharp'/><category term='juerga'/><category term='hardware'/><category term='revista'/><category term='certificados'/><category term='teoria'/><category term='almacenamiento'/><category term='alegría'/><category term='servicios de directorio'/><category term='bases de datos'/><category term='XML'/><category term='Java'/><category term='blog'/><category term='retorno'/><category term='open flash chart'/><category term='administración'/><category term='gestor contenidos'/><category term='redes inalámbricas'/><category term='programación'/><category term='proyectos'/><category term='cooperación al desarrollo'/><category term='twitter'/><category term='repositorios'/><category term='encriptación'/><category term='HTML'/><category term='ssl'/><category term='telecomunicaciones rurales'/><category term='casamiento'/><category term='asp.net'/><category term='EHAS'/><category term='mono'/><category term='J2EE'/><title type='text'>N-Idea. Nuevas Ideas</title><subtitle type='html'>asp.net, c#, java, windows forms, sql server, php, ajax, javascript, linux, software libre, servidores, dicom, biomedicina, ...
&lt;br&gt;&lt;b&gt;&lt;a href="http://www.nidea-soluciones.com"&gt;N-Idea&lt;/a&gt;&lt;/b&gt; de muchos temas... o eso pensamos.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>55</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-37408564.post-7761518430741946913</id><published>2010-11-19T16:14:00.000Z</published><updated>2010-11-19T16:15:05.310Z</updated><title type='text'>Acceder a controles creados dinámicamente desde servidor en ASP.net</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;Un tema que siempre he considerado un inconveniente en asp.net es la dificultad de acceder a los datos de los controles creados dinámicamente. En este pequeño artículo voy a mostrar una pequeña solución para poder crear controles desde javascript y desde servidor y poder obtener los valores introducidos.&lt;br/&gt;&lt;b&gt;&lt;br/&gt;&lt;big&gt;Creación de Controles&lt;/big&gt;&lt;/b&gt;&lt;br/&gt;Vamos a crear una página aspx con tres botones: uno que cree botones vía javascript, otro que cree cajas de texto desde javascript y otro que cree un textbox desde servidor:&lt;br/&gt;&lt;img width='100%' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/TOabYeYlkAI/AAAAAAAAA2s/HhI2L6ljdms/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;&lt;br/&gt;La función javascript que crea los controles es la siguiente:&lt;br/&gt;&lt;img width='100%' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/TOabyNYYxpI/AAAAAAAAA2w/V6KROOPtAgI/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;Unicamente creamos, en base al tipo, un input de tipo submit si es boton o un input de tipo text si el tipo es texto. Al ejecutar la página podemos crear tantos controles como queramos pulsando sobre los botones. El código del evento del botón &lt;b&gt;botonCrearTexto&lt;/b&gt; se ejecuta en el servidor y crea un textbox dinámicamente:&lt;br/&gt;&lt;img width='100%' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/TOadQISgV1I/AAAAAAAAA20/4YJ5D0IhPH4/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;La idea ahora es poder obtener los valores introducidos en los campos de texto y el botón que se ha pulsado:&lt;br/&gt;&lt;img width='100%' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/TOad4V0n2oI/AAAAAAAAA24/SDD65q1k8Uo/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;Capturar el valor de los controles&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;El objetivo ahora es que al pulsar sobre cualquier botón podamos acceder a la información del botón pulsado y al contenido de los diferentes textBox que se hayan creado desde el servidor. El quid del meollo es la clase HttpContext, en la que se mantiene la información intercambiada entre el cliente y el servidor:&lt;br/&gt;&lt;img width='100%' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/TOaguwTe5wI/AAAAAAAAA28/Q0drJpCqXfk/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;Dentro de la colección &lt;b&gt;HttpContext.Current.Request.Form.AllKeys&lt;/b&gt; se encuentran todos los valores posteados desde el cliente, el control que realiza el post, el valor de los controles que disponen de valor, el viewstate de la página y el eventvalidation en el caso de controles de servidor. Podemos recorrer esta colección y acceder al valor de los input de tipo texto.&lt;br/&gt;&lt;br/&gt;No tenemos en cuentra los controles que empiecen por __ porque son propios de asp.net.&lt;br/&gt;&lt;br/&gt;El resultado es que al pulsar sobre cualquier botón, en pantalla mostramos los valores introducidos:&lt;br/&gt;&lt;img width='100%' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/TOah0yBVwmI/AAAAAAAAA3A/kfJLNt_Lpmw/%5BUNSET%5D.png?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;Conclusiones&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;Muchas veces nos vemos en el problema de controles dinámicos y no podemos resolverlo de forma fácil con asp.net. Con este artículo espero facilitaros la vida. Dependerá del desarrollador evolucionar esta solución para repintar los controles y asignarles el valor entre posts para que no desaparezcan.&lt;br/&gt;&lt;br/&gt;Como siempre espero que os haya gustado esta pequeña aportación&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7761518430741946913?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7761518430741946913/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7761518430741946913' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7761518430741946913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7761518430741946913'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2010/11/acceder-controles-creados-dinamicamente.html' title='Acceder a controles creados dinámicamente desde servidor en ASP.net'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_uUP4eiIAPJ8/TOabYeYlkAI/AAAAAAAAA2s/HhI2L6ljdms/s72-c/%5BUNSET%5D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7433168134152316153</id><published>2010-10-11T09:49:00.002Z</published><updated>2010-10-11T09:54:50.647Z</updated><title type='text'>Control de Usuario "Contador de filas de DataGridView" en C#</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;Hace poco me encontré con el problema de tener un proyecto en c# de ventanas con muchos datagridview al que había que ponerle a cada gridview un contador de filas. La primera opción era poner en cada pantalla un &lt;b&gt;label &lt;/b&gt;y programar el evento &lt;b&gt;DataBindingComplete &lt;/b&gt;para que se muestre en pantalla. El engorro era que había que tocar muchas pantallas y tocar el código de todas así que me plantee hacer un control de usuario que pudiera insertar en cada página, que tuviera una propiedad en la que le indicará el control gridview y me sirviera para todas las pantallas. Así que, ¡manos a la obra!&lt;br /&gt;&lt;br /&gt;Podéis descargar el código de este control &lt;a href="http://www.nidea-soluciones.com/descargas/ucNumeroRegistrosGridView.rar"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;big&gt;El código&lt;/big&gt;&lt;/b&gt;&lt;br /&gt;El quid del control es definir una propiedad pública en la que podamos definir el gridview y enlazar el evento DataBindingComplete.&lt;br /&gt;&lt;br /&gt;&lt;img width="100%" src="http://lh3.ggpht.com/_uUP4eiIAPJ8/TLLZ-Uv_pII/AAAAAAAAA1g/z592Va3OBcE/%5BUNSET%5D.jpg?imgmax=800" style="max-width: 800px;" title="" alt="" /&gt;&lt;br /&gt;La parte de diseño del control es la siguiente:&lt;br /&gt;&lt;img src="http://lh3.ggpht.com/_uUP4eiIAPJ8/TLLaUs6exDI/AAAAAAAAA1k/45AKZSb1o1A/%5BUNSET%5D.jpg?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;b&gt;&lt;big&gt;Insertar el control en el Formulario&lt;/big&gt;&lt;/b&gt;&lt;br /&gt;Una vez creado el control lo insertaremos en el formulario, en la ubicación que queramos y especificaremos la propiedad GRIDVIEW para que el control obtenga el número de filas.&lt;br /&gt;&lt;br /&gt;&lt;img width="100%" src="http://lh3.ggpht.com/_uUP4eiIAPJ8/TLLbCssqyiI/AAAAAAAAA1o/oM96_0v3GUs/%5BUNSET%5D.jpg?imgmax=800" style="max-width: 800px;" title="" alt="" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://lh6.ggpht.com/_uUP4eiIAPJ8/TLLba5cE-VI/AAAAAAAAA1s/1ALKpmAYvoA/%5BUNSET%5D.jpg?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;br /&gt;Podemos incluir tantos controles como queramos. En el momento en que se realice el evento databindingcomplete, el control actualizará el número de filas:&lt;br /&gt;&lt;img width="100%" src="http://lh4.ggpht.com/_uUP4eiIAPJ8/TLLb4MGR3uI/AAAAAAAAA1w/qsUNN0WXJgQ/%5BUNSET%5D.jpg?imgmax=800" style="max-width: 800px;" title="" alt="" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;big&gt;Conclusión&lt;/big&gt;&lt;/b&gt;&lt;br /&gt;Este es un control muy sencillo pero que arregla una situación en la que habría que haber cambiado mucho código. Además, la utilización de controles de usuario permite un código sostenible y mejorable. En cualquier momento podemos asignarle más funcionalidades o cambiarle el aspecto y se aplicará a todas las pantallas sin tener que cambiar nada.&lt;br /&gt;&lt;br /&gt;Como siempre, espero que os haya gustado y os sirva de utilidad.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7433168134152316153?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7433168134152316153/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7433168134152316153' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7433168134152316153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7433168134152316153'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2010/10/control-de-usuario-de-filas-de.html' title='Control de Usuario &quot;Contador de filas de DataGridView&quot; en C#'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_uUP4eiIAPJ8/TLLZ-Uv_pII/AAAAAAAAA1g/z592Va3OBcE/s72-c/%5BUNSET%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-6172730071247439914</id><published>2010-10-05T12:56:00.000Z</published><updated>2010-10-05T15:01:08.528Z</updated><title type='text'>Plugin "Insertar HTML" para FCKEditor</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;Hace ya bastante tiempo que utilizo el editor WYSIWYG &lt;a target='_blank' href='http://www.ckeditor.com'&gt;FCKEditor&lt;/a&gt; y de siempre me ha parecido una herramienta excepcional. En este artículo voy a desarrollar un plugin que utilizo y que me ha venido muy bien para muchos proyectos. Este plugin es muy simple, un botón para que el usuario pueda pegar un HTML y que se inserte donde tenga puesto el cursor. La razón es que para usuarios no acostumbrados a HTML, explicarles que para, p.e. enlazar con un mapa de google, tienen que pulsar sobre el botón &lt;b&gt;Fuente HTML&lt;/b&gt; y localizar la ubicación en el código HTML y pegar allí el código de Google Maps es, en muchos casos, imposible.&lt;br/&gt;&lt;br/&gt;Puedes descargar los &lt;a href='http://www.nidea-soluciones.com/descargas/insertarHtml.rar' target='_blank'&gt;códigos de este post aquí&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;1. El Objetivo&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;El objetivo es conseguir lo siguiente, un botón en el editor que al pulsarse muestre la ventana de insertar HTML:&lt;br/&gt;&lt;img width='100%' alt='' title='' style='max-width: 800px;' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/TKs1sjjbMrI/AAAAAAAAA1I/kk03r1vBbU8/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;img height='350' width='298' style='max-width: 800px;' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/TKs2FlOv5-I/AAAAAAAAA1M/VSyEPJ3POXo/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;2. Ficheros necesarios&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;Lo primero es conocer la estructura para crear un plugin para FCKEditor. En realidad es muy simple, necesitaremos crear una carpeta en el directorio &lt;b&gt;/editor/plugins&lt;/b&gt; (en este caso &lt;b&gt;insertarHtml&lt;/b&gt; es el nombre de la carpeta) del FCKEditor que contenga los siguientes ficheros:&lt;br/&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;fckplugin.js&lt;/b&gt;: fichero javascript en el que se definen las propiedades del plugin: formato de la ventana a mostrar, icono, nombre del plugin, ...&lt;/li&gt;&lt;li&gt;&lt;b&gt;insertarHtml.png&lt;/b&gt;: imagen para el icono del botón en el FCKEditor.&lt;/li&gt;&lt;li&gt;&lt;b&gt;insertarHtml.php&lt;/b&gt;: página que se muestra al pulsar el botón. En este caso es PHP pero puede ser perfectamente HTML o ASPX o lo que se quiera.&lt;/li&gt;&lt;/ol&gt;Finalmente, necesitamos dar de alta el plugin en el fichero fckconfig.js que está en el directorio raiz del FCKEditor. Vamos a ir viendo paso a paso cada uno de los ficheros.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;3. fckplugin.js&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;En este fichero se configuran los datos generales del plugin. Lo primero es registrar el comando:&lt;br/&gt;&lt;br/&gt;&lt;small&gt;&lt;font face='Courier New'&gt;FCKCommands.RegisterCommand( 'Insertar_Html', new FCKDialogCommand( 'Insertar código HTML', 'Insertar código HTML', FCKConfig.PluginsPath + 'insertarHtml/insertarHtml.php', 400, 400 ) ) ;&lt;/font&gt;&lt;/small&gt;&lt;br/&gt;&lt;br/&gt;Indicamos qué página se abre en la nueva ventana, el tamaño de la ventana, el nombre que aparece en la ventana, etc. Lo siguiente es crear el botón:&lt;br/&gt;&lt;br/&gt;&lt;small&gt;&lt;font face='Courier New'&gt;var oHTMLItem        = new FCKToolbarButton( 'Insertar_Html', 'Insertar código HTML en la posición del cursor' ) ;&lt;br/&gt;oHTMLItem.IconPath    = FCKConfig.PluginsPath + 'insertarHtml/insertarHtml.png' ;&lt;/font&gt;&lt;/small&gt;&lt;br/&gt;&lt;br/&gt;y finalmente, registramos el elemento:&lt;br/&gt;&lt;br/&gt;&lt;small&gt;&lt;font face='Courier New'&gt;FCKToolbarItems.RegisterItem( 'Insertar_Html', oHTMLItem ) ;&lt;/font&gt;&lt;/small&gt;&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;4. insertarHtml.php&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;En el fichero insertarHtml.php es donde se genera la acción. Es la pantalla que se llama cuando el usuario pulsa sobre el botón. La página tiene una parte de presentación HTML y otra de código PHP. La primera parte es:&lt;br/&gt;&lt;img width='100%' alt='' title='' style='max-width: 800px;' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/TKs4FuHEAcI/AAAAAAAAA1Q/ZL98bPp0kK8/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;&lt;br/&gt;Es importante la parte inicial de javascript que es la que coge la referencia al FCKEditor que ha llamado a esta ventana. La parte de código es la que se ejecuta cuando se pulsa sobre el botón &lt;b&gt;btnInsertar&lt;/b&gt;:&lt;br/&gt;&lt;br/&gt;&lt;img width='100%' alt='' title='' style='max-width: 800px;' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/TKs4nFQU8OI/AAAAAAAAA1U/BqAVyopjTOE/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;Lo que hacemos es generar el código javascript que inserta el código HTML en la posición del cursor y lo pasamos a la variable &lt;b&gt;codigoJavascript&lt;/b&gt;, de la que se hace un echo en la parte HTML. Seguidamente, cerramos la ventana y volvemos a la pantalla del FCEditor.&lt;br/&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;5. fckconfig.js&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;Lo último es dar de alta el botón en la toolbar de nuestro FCKEditor y utilizarlo. Para ello tenemos que modificar el fichero fckconfig.js que se encuentra en el directorio raiz del FCKEditor. Lo primero que tenemos que hacer es añadir el plugin:&lt;br/&gt;&lt;br/&gt;&lt;small&gt;&lt;font face='Courier New'&gt;FCKConfig.Plugins.Add( 'insertarHtml' ) ;&lt;/font&gt;&lt;/small&gt;&lt;br/&gt;&lt;br/&gt;y finalmente, incluir el comando en la toolbarset que estemos utilizando. Yo, p.e., he incluido el botón en la toolbarset default, al final:&lt;br/&gt;&lt;br/&gt;&lt;font face='Courier New'&gt;&lt;small&gt;FCKConfig.ToolbarSets["Default"] = [&lt;br/&gt;    ['Source','DocProps','-','Preview','-','Templates'],&lt;br/&gt;    ['Cut','Copy','Paste','PasteText','PasteWord','-','Print'],&lt;br/&gt;    ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],&lt;br/&gt;    '/',&lt;br/&gt;    ['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],&lt;br/&gt;    ['OrderedList','UnorderedList','-','Outdent','Indent','Blockquote','CreateDiv'],&lt;br/&gt;    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],&lt;br/&gt;    ['Link','Unlink','Anchor'],&lt;br/&gt;    ['Image','Flash','Table','Rule','Smiley','SpecialChar'],&lt;br/&gt;    '/',&lt;br/&gt;    ['FontFormat','FontSize'],&lt;br/&gt;    ['TextColor','BGColor'],&lt;br/&gt;    ['FitWindow','ShowBlocks','-',&lt;b&gt;&lt;i&gt;&lt;big&gt;'Insertar_Html'&lt;/big&gt;&lt;/i&gt;&lt;/b&gt;]&lt;br/&gt;];&lt;br/&gt;&lt;/small&gt;&lt;/font&gt;&lt;br/&gt;&lt;big&gt;&lt;b&gt;6. Conclusión&lt;/b&gt;&lt;/big&gt;&lt;br/&gt;Este plugin es muy sencillo pero muy útil para aquellos proyectos en los que el usuario del FCKEditor no tiene conocimientos de HTML pero quiere incluir código de otras webs como pueden ser VIMEO, YouTube, Google Maps, Facebook. Cada día es más normal enlazar HTML en nuestras páginas y este plugin nos facilita la tarea.&lt;br/&gt;&lt;br/&gt;Ejemplo: copio la localización de mi pueblo en google maps en la pantalla del plugin:&lt;br/&gt;&lt;img style='max-width: 800px;' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/TKs7G1tV3EI/AAAAAAAAA1Y/h5cmaj3HdXA/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;Al pulsar sobre&lt;b&gt; Insertar HTML&lt;/b&gt;, se inserta el código donde tengo colocado el cursor:&lt;br/&gt;&lt;img width='100%' alt='' title='' style='max-width: 800px;' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/TKs75zfb_3I/AAAAAAAAA1c/biOfXM2_fx4/%5BUNSET%5D.jpg?imgmax=800'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Espero que os haya gustado este artículo. En breve más...&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-6172730071247439914?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/6172730071247439914/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=6172730071247439914' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/6172730071247439914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/6172730071247439914'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2010/10/plugin-html-para-fckeditor.html' title='Plugin &amp;quot;Insertar HTML&amp;quot; para FCKEditor'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_uUP4eiIAPJ8/TKs1sjjbMrI/AAAAAAAAA1I/kk03r1vBbU8/s72-c/%5BUNSET%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7448138943701392392</id><published>2010-05-21T04:24:00.000Z</published><updated>2010-05-28T12:07:12.109Z</updated><title type='text'>Control de acceso web "Dinámica de Tecleo"</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;div align='justify'&gt;Hace mucho, mucho tiempo que no escribo en el blog porque he estado muy ocupado pero al fin tengo un rato, así que, manos a la obra.&lt;/div&gt;El artículo va sobre la seguridad y el control de acceso a aplicaciones web y quiero exponer un trabajo de investigación que realicé para un postgrado de la UNED, el control de acceso a aplicaciones web utilizando&lt;font color='#999900'&gt;&lt;b&gt; la dinámica de tecleo.&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;&lt;blockquote&gt;Podéis descargar los códigos y el script de creación de base de datos &lt;a href='http://www.nidea-soluciones.com/Descargas/DinamicaTecleo.rar'&gt;aquí&lt;/a&gt;.&lt;br/&gt;&lt;/blockquote&gt;&lt;br/&gt;&lt;b&gt;&lt;font color='#cc9900' class='Apple-style-span'&gt;Antecedentes&lt;/font&gt;&lt;/b&gt;&lt;br/&gt;A la hora de control el acceso a recursos compartidos, se utilizan tres técnicas distintas, basadas en tres premisas:&lt;ul&gt;&lt;li&gt;&lt;b&gt;Algo que el usuario sabe:&lt;/b&gt; esta es la premisa para el 99% de sitios, el usuario conoce un login y un password. Lógicamente, si un atacante consigue obtener esa información podrá suplantar la identidad. Este es, por norma general, el método más inseguro puesto que existen numerosas técnicas para robar las claves y, además, los usuarios no suelen usar claves alfanuméricas complejas porque son difíciles de recordar.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Algo que el usuario tiene:&lt;/b&gt; esta es la segunda premisa en la que el usuario es poseedor de algo que solo tiene él. Los sistemas que se basan en esto son los que utilizan tarjetas de coordenadas o certificados digitales, por ejemplo. Este sistema es más complicado porque se suele combinar con el primero y el atacante tiene que, o bien obtener una copia de lo que el usuario tiene o robárselo, además de obtener el usuario y la contraseña.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Algo que el usuario es:&lt;/b&gt; esta es la última premisa y es en la que se basa&lt;font color='#339999' class='Apple-style-span'&gt;&lt;b&gt; la seguridad biométrica&lt;/b&gt;&lt;/font&gt;. Las personas disponemos de rasgos o de actitudes que nos hacen únicos en el mundo. Usando esos rasgos físicos o esas actitudes o comportamientos que están impresos en nuestro cerebro se pueden generar patrones de seguridad que son mucho más complejos de romper que los dos anteriores. Usando este tipo de técnicas, el atacante, tendrá que copiar rasgos físicos (iris, retina, huella dactilar, forma de mano,...) o comportamientos (firma caligráfica, dinámica de tecleo,...) algo que en algunos casos es imposible y en otros en muy complicado.&lt;/li&gt;&lt;/ul&gt;Lo ideal es la utilización de forma combinada de las tres técnicas para obtener un sistema de acceso lo más seguro posible. En este artículo voy a exponer una forma práctica de implementar un sistema de control observando&lt;b&gt; &lt;font color='#669966' class='Apple-style-span'&gt;la forma de teclear de los usuarios&lt;/font&gt;&lt;/b&gt; (dinámica de tecleo) para determinar si el usuario ha sido suplantado o no.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;font color='#cc9900' class='Apple-style-span'&gt;Dinámica de Tecleo&lt;/font&gt;&lt;/b&gt;&lt;br/&gt;La dinámica de tecleo es una técnica que se basa en el principio de que la acción de escribir en el teclado una palabra o frase (contraseña) muy frecuentemente hace que el acto de escribirla se convierta en algo &lt;b&gt;&lt;font color='#3399ff' class='Apple-style-span'&gt;inconsciente y automático&lt;/font&gt;&lt;/b&gt;. Esto provoca que ese gesto sea característico nuestro porque influyen tanto procesos mentales que se convierte en una especie de huella dactilar. Los parámetros que se tienen en cuenta a la hora de mesurar la dinámica de tecleo son dos, el tiempo de pulsación de cada tecla y el tiempo entre pulsaciones. En base a estos dos parámetros se pueden &lt;b&gt;&lt;font color='#669933' class='Apple-style-span'&gt;crear patrones de comportamiento&lt;/font&gt;&lt;/b&gt; que nos pueden decir si un usuario es o no es quién dice ser, independientemente de que la contraseña sea correcta o no.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;font color='#cc9900' class='Apple-style-span'&gt;Diseño del sistema de control de acceso&lt;/font&gt;&lt;/b&gt;&lt;br/&gt;Lo que vamos a hacer es un sistema mixto de control. Por un lado, el usuario va a tener que introducir su usuario y contraseña, se validarán las credenciales y además se controlará la dinámica de tecleo de la contraseña. Dicho tecleo se comparará con un patrón del usuario para ver qué probabilidad hay de que sea realmente nuestro usuario y no un suplantador. Hay que tener en cuenta que cuando hablamos de biometría siempre consideramos probabilidades y no certezas. A la hora de configurar el sistema tendremos que elegir cuál es el umbral a partir del cuál consideraremos que el usuario es un suplantador. Cuanto mayor sea ese umbral, mayor será la seguridad pero más falsos negativos dará y cuanto menor sea el umbral, menor la seguridad pero menos falsos negativos. Cada uno modificará este umbral para que se adecue a sus necesidades y pruebas.&lt;br/&gt;&lt;br/&gt;En nuestro sistema vamos a tener 3 módulos diferenciados:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;Módulo de captura de datos: es el encargado de capturar los datos de pulsación y tiempo entre pulsaciones en el lado del cliente. Este módulo estará implementado en Javascript.&lt;/li&gt;&lt;li&gt;Módulo de entrenamiento: parte del sistema encargada de generar el patrón con el que se comparan las muestras a identificar.&lt;/li&gt;&lt;li&gt;Módulo de autenticación: parte encargada de decidir si un usuario es quién dice ser o no.&lt;/li&gt;&lt;/ul&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;Generación del patrón&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Lo primero es la generación del patrón para cada usuario. Tomemos por ejemplo, la palabra MANOLO, para la dinámica de tecleo tenemos que tomar las siguientes muestras:&lt;br/&gt;&lt;img height='54' width='299' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/S_-ktU7irMI/AAAAAAAAAd0/x5fpycNrc_U/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;Tomaremos una muestre para el tiempo de pulsación de cada letra y el tiempo entre pulsaciones. Para generar nuestro patrón tomaremos N muestras de la palabra clave MANOLO escritas por nuestro usuario, cada una de las muestras tendrá 2*n-1 posiciones siendo n el número de caracteres de la palabra. En este caso cada muestra o vector que guardamos tendrá 11 posiciones:&lt;br/&gt;&lt;img height='137' width='415' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/S_-lih3ggmI/AAAAAAAAAd4/7GAtp9zkd1c/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;Una vez que disponemos de las muestras, tendremos que obtener un vector con las medias de cada posición y otro con las varianzas de cada posición.&lt;br/&gt;&lt;img src='http://lh6.ggpht.com/_uUP4eiIAPJ8/S_-mSSjpPnI/AAAAAAAAAd8/HKf1X_djRgU/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;div&gt;&lt;div align='justify'&gt;&lt;img src='http://lh4.ggpht.com/_uUP4eiIAPJ8/S_-mWCcQdhI/AAAAAAAAAeA/OzJIk6kMoy8/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;El patrón del usuario será, por lo tanto, un vector de 11 posiciones con la media de cada uno de los tiempos de pulsación y tiempo entre pulsaciones y otro con un vector de 11 posiciones con las varianzas de cada uno de los tiempos. Este patrón lo almacenaremos en una base de datos para, posteriormente, poder realizar la comparación en el control de acceso.&lt;br/&gt;&lt;br/&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;Función de Scoring&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;La función de Scoring es la encargada de determinar el grado de similitud entre la clave introducida por el usuario que se quiere autenticar y el patrón almacenado en la base de datos.&lt;br/&gt;&lt;img height='220' width='412' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/S_-nTg2pkFI/AAAAAAAAAeE/4KL2LFCGr1s/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;Una vez obtenido el vector de valores SCORE, realizamos una media entre ellos para obtener un solo valor a comparar:&lt;br/&gt;&lt;img src='http://lh4.ggpht.com/_uUP4eiIAPJ8/S_-nfaErSVI/AAAAAAAAAeI/zzCH080rzw4/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;Este valor se comparará con el valor de UMBRAL definido en el sistema y determinará si el usuario es o no es quién dice ser.&lt;br/&gt;&lt;br/&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;Diseño Real del Sistema&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Vamos a ver cómo, podemos diseñar en la vida real un sistema de control de acceso de este tipo. El flujo del sistema es el siguiente:&lt;br/&gt;&lt;img height='146' width='430' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/S_-oB7Y7V4I/AAAAAAAAAeM/Bfh7wbL1Ums/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;Para la implementación del sistema vamos a utilizar ASP.net (c#) como lenguaje de servidor, SQL Server como gestor de base de datos y Javascript para el control del tecleo.&lt;br/&gt;&lt;br/&gt;&lt;font color='#006600'&gt;&lt;b&gt;Modelo de Base de Datos&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;En nuestro sistema vamos a tener dos tablas, una para la información de las claves del usuario y otra para almacenar los patrones:&lt;br/&gt;&lt;img height='302' width='430' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/S_-oqKHPALI/AAAAAAAAAeQ/vvhHIKQRSw8/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;font color='#006600'&gt;&lt;b&gt;Interfaz Web&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Para nuestro ejemplo, se ha unificado en una sola interfaz el entrenamiento del sistema junto con el acceso al mismo:&lt;br/&gt;&lt;img height='335' width='412' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/S_-pLk3LzfI/AAAAAAAAAeU/mlFeVs8F7AY/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;El usuario tendrá que introducir su usuario y contraseña y, además, la frase de control que se ha utilizado para generar el patrón. En la parte de entrenamiento, el usuario puede ir introduciendo nuevas muestras, cuantas más muestras se tengan mayor será el acierto del sistema.&lt;br/&gt;&lt;br/&gt;Cuando se pulsa sobre el botón "Acceder", el sistema devuelve en una pantalla tres valores:&lt;br/&gt;&lt;img src='http://lh4.ggpht.com/_uUP4eiIAPJ8/S_-qIH5gSdI/AAAAAAAAAeY/Ti4Ef-un_X4/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;ul&gt;&lt;li&gt;Score Total: valor devuelto por la función de Scoring teniendo en cuenta tanto el tiempo de pulsación como el tiempo entre pulsaciones.&lt;/li&gt;&lt;li&gt;Score Pulsación: valor teniendo en cuenta solamente el tiempo de pulsación.&lt;/li&gt;&lt;li&gt;Score Entre: valor teniendo en cuenta solamente el tiempo entre pulsaciones.&lt;/li&gt;&lt;/ul&gt;&lt;font color='#006600'&gt;&lt;b&gt;Lógica del Cliente&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;En el lado del cliente, se ejecuta la lógica necesaria para capturar los datos de las muestras y enviarlos al servidor. Estas funciones se encuentran en Javascript (ver los códigos del proyecto) y preparadas para los exploradores más utilizados. El flujo de llamadas es el siguiente:&lt;br/&gt;&lt;img height='189' width='417' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/S_-q5_LVP2I/AAAAAAAAAec/YdSqvsqVFZk/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;Para el caso de la comprobación del acceso al sistema, las llamadas Javascript son las siguientes:&lt;br/&gt;&lt;img height='179' width='413' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/S_-rGQOnAjI/AAAAAAAAAeg/dcm1TU9-cY0/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;font color='#006600'&gt;&lt;b&gt;Lógica del Servidor&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Toda la lógica de la generación del patrón, la comprobación del usuario y la generación de la función de Scoring se realiza en el servidor. La comunicación entre el cliente y el servidor se realiza mediante llamadas a un servicio web llamado DinamicaTecleo.asmx ell cuál dispone de dos métodos públicos: RecibirMuestras y ComprobarAcceso.&lt;br/&gt;&lt;br/&gt;El método RecibirMuestras es el encargado de recibir las muestras, formatearlas y guardarlas en base de datos:&lt;br/&gt;&lt;img height='212' width='418' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/S_-sImSf6KI/AAAAAAAAAek/L9jNWO6xs8E/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;El método ComprobarAcceso es el encargado de comprobar que el usuario es quien dice ser o no. Este método devuelve los tres valores que se muestran por pantalla:&lt;br/&gt;&lt;img height='200' width='425' src='http://lh3.ggpht.com/_uUP4eiIAPJ8/S_-slfxCJjI/AAAAAAAAAeo/Y0QtnuCeCEk/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;Los datos del patrón se almacenan en la base de datos de la siguiente manera:&lt;br/&gt;&lt;br/&gt;&lt;img height='187' width='423' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/S_-s1PhGpbI/AAAAAAAAAes/uRFA9G8mJIo/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;br/&gt;&lt;br/&gt;Se guardan las muestras de entrenamiento para cada usuario separadas por comas, en una columna los milisegundos de pulsación de cada tecla y en la otra los milisegundos entre pulsaciones.&lt;br/&gt;&lt;br/&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;Conclusión&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Las conclusiones que se obtuvieron con los individuos que realizaron las pruebas fueron que, efectivamente, la dinámica de tecleo es una buena técnica complementaria al control mediante usuario y contraseña. Para que el sistema sea efectivo, la fase de entrenamiento debe ser extensa para disponer de muchas muestras. También es bueno eliminar aquellas muestras muy alejadas de la media.&lt;br/&gt;El sistema funciona de forma óptima cuando la frase de control se compone de letras y números sin sentido puesto que es cuando el cerebro tiene que pensar qué teclas pulsar y tiene que mover las manos de su posición natural. En el caso de frases con sentido es más fácil la suplantación porque la posición de las manos y la cadencia es más natural.&lt;br/&gt;&lt;br/&gt;Un fallo que no pude resolver en el sistema se produce cuando el usuario escribe tan rápido que antes de soltar una de las teclas ya ha pulsado la siguiente, generando un tiempo de pulsación negativo. Mediante javascript no fui capaz de controlar ese caso y obtenía un error. Si alguien lo corrige le agradecería que lo comentara.&lt;br/&gt;&lt;br/&gt;En fin, creo que la dinámica de tecleo es un sistema fácil y barato de control biométrico, no necesitamos aparatos externos ni inversiones en dinero. Puede introducirse de forma transparente en un sistema ya establecido y puede aumentar el nivel de seguridad exponencialmente.&lt;br/&gt;&lt;br/&gt;Espero que os haya gustado este artículo.&lt;br/&gt;&lt;/div&gt;&lt;br/&gt;&lt;br/&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/37408564-7448138943701392392?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7448138943701392392/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7448138943701392392' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7448138943701392392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7448138943701392392'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2010/05/control-de-acceso-web-de-tecleo_21.html' title='Control de acceso web &amp;quot;Dinámica de Tecleo&amp;quot;'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_uUP4eiIAPJ8/S_-ktU7irMI/AAAAAAAAAd0/x5fpycNrc_U/s72-c/%5BUNSET%5D.gif?imgmax=800' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-1246292125889213758</id><published>2009-08-22T13:19:00.005Z</published><updated>2009-08-22T14:23:37.986Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='microblogging'/><category scheme='http://www.blogger.com/atom/ns#' term='web 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><title type='text'>twitter desde línea de comandos</title><content type='html'>Twitter, ese gran amigo de muchos y mal endémico de la web 2.0 al que yo aún no había sucumbido. El enjuto hermano bastardo del "blogger". La forma de que la web 2.0 convierta tu vida en Tu Vida 2.0, aquí en Mundo Real™.&lt;br /&gt;&lt;br /&gt;¿Y qué es lo que le preocupa a un usuario de GNU/Linux cuando conoce Twitter? ¿me quedaré enganchado a ésto por el resto de mis días? ¿seré hallado con 80 años muerto relatando mi propia agonía en 140 caracteres? ...&lt;br /&gt;&lt;br /&gt;... pues no ...&lt;br /&gt;&lt;br /&gt;... la verdadera pregunta es ... ¿se podrá hacer ésto desde línea de comandos? Y obviamente hay como otras 8000 personas a las que eso ya se les ocurrió antes, así que la respuesta a vuestras plegarias sale con un googleo simple.&lt;br /&gt;&lt;br /&gt;Esta es una entrada chorra (tengo algunas más interesantes en mente y proyecto), así que sólo pondré las 2 formas que me han resultado más divertidas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Fórmula 1 -- postear en twitter usando curl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Gracias al API de twitter, se puede usar curl para hacer un sencillo micro-post con un comando tan chorra como...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;curl -u usuario:contraseña -d status="Tu mensaje"  http://twitter.com/statuses/update.xml&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Fórmula 2 -- Twitter Tools&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esta aplicación escrita en python es la que más me ha gustado para esta tarea (sólo he inspeccionado 4 o 5, tampoco es que tenga mucho criterio). Es sencillita y te permite ver tu twitter con sólo hacer...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;twitter&lt;/blockquote&gt;&lt;br /&gt;¿Fácil no? Veamos 2 formas de instalarla.&lt;br /&gt;&lt;br /&gt;La primera es la más sencilla, y consiste en instalar el paquete apropiado desde línea de comandos. Algo tan fácil como...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;sudo aptitude install python-twitter&lt;/blockquote&gt;&lt;br /&gt;La otra forma consiste en irse a la página web (&lt;a href="http://mike.verdone.ca/twitter/"&gt;http://mike.verdone.ca/twitter/&lt;/a&gt;) y descargarse el código fuente (en tar.gz). Luego lo descomprimimos con...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;tar -xvzf twitter-&lt;version&gt;.tar.gz&lt;/version&gt;&lt;/blockquote&gt;&lt;br /&gt;ahora nos intalamos el paquete python-setuptools con...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;sudo aptitude install python-setuptools&lt;/blockquote&gt;&lt;br /&gt;accedemos a la carpeta twitter dentro de la carpeta descomprimida y desde dentro hacemos...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;sudo easy_install twitter&lt;/blockquote&gt;&lt;br /&gt;La ventaja de usar la versión descargada es que como es lógico, te descargas la última versión disponible que siempre va a estar por encima de la disponible en los repositorios. La desventaja, que no tienes la actualización automática que te dan los repositorios. Para algo con tan poco calado e importancia, yo personalmente recomiendo usar la instalación desde los repositorios.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;La configuración&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para ahorrarnos el tener que poner el usuario y contraseña cada vez que vamos a consultar o escribir en nuestro twitter, podemos crear un fichero en ~/.twitter que tenga un contenido como el siguiente...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;[twitter]&lt;br /&gt;email: mi_usuario&lt;br /&gt;password: mi_clave&lt;br /&gt;format: ansi&lt;br /&gt;prompt: '[cyan]twitter[R]'&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;...que hará que no tengáis que introducir usuario y clave, y además pondrá de colorines el resultado de las lecturas de  forma que será más entretenido de leer :).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;El resultado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y ahora el resultado. Un ejemplo...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;twitter set "Python Twitter Tools mola, lo recomiendo realmente a todos/as"&lt;/blockquote&gt;produciría un resultado que podríamos ver desde línea de comandos con el comando "twitter" como os pongo a continuación...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Odz8IS0Tz3k/So_92t9vmII/AAAAAAAAAmw/go3gKpQFA2I/s1600-h/twitter-cmd-3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 117px;" src="http://3.bp.blogspot.com/_Odz8IS0Tz3k/So_92t9vmII/AAAAAAAAAmw/go3gKpQFA2I/s200/twitter-cmd-3.png" alt="" id="BLOGGER_PHOTO_ID_5372791996969621634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Y visto desde la web de twitter...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Odz8IS0Tz3k/So_-G9jySGI/AAAAAAAAAm4/4wFNQqMumYI/s1600-h/twitter-cmd.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 86px;" src="http://3.bp.blogspot.com/_Odz8IS0Tz3k/So_-G9jySGI/AAAAAAAAAm4/4wFNQqMumYI/s200/twitter-cmd.png" alt="" id="BLOGGER_PHOTO_ID_5372792276033620066" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Y bueno, para quienes finalmente decidáis usar este sistema de microblogging ya iréis descubriendo que desde la Ptt (Python twitter tools) se pueden hacer muchas más cosas. Pero eso ya os lo dejo a vosotros/as.&lt;br /&gt;&lt;br /&gt;Un abrazo a todos/as.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-1246292125889213758?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/1246292125889213758/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=1246292125889213758' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1246292125889213758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1246292125889213758'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/08/twitter-desde-linea-de-comandos.html' title='twitter desde línea de comandos'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Odz8IS0Tz3k/So_92t9vmII/AAAAAAAAAmw/go3gKpQFA2I/s72-c/twitter-cmd-3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-6094608588668728461</id><published>2009-08-10T09:35:00.002Z</published><updated>2009-08-10T09:38:41.646Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='itextsharp'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>Códigos del motor de informes dinámicos en PDF</title><content type='html'>Debido a la demanda de los códigos, he realizado un pequeño proyecto sobre la entrada "&lt;a href="http://nidea-soluciones.blogspot.com/2008/03/motor-de-informes-dinmicos-con.html"&gt;Motor de informes dinámicos con iTextSharp(I)&lt;/a&gt;" . Os recomiendo leer primero el post para poder entender los códigos correctamente y sacarles el máximo partido.&lt;br /&gt;&lt;br /&gt;Podéis descargar el proyecto desde &lt;a href="http://www.nidea-soluciones.com/Descargas/PruebaITextSharp.rar"&gt;aquí&lt;/a&gt;. Espero que os sea de utilidad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-6094608588668728461?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/6094608588668728461/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=6094608588668728461' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/6094608588668728461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/6094608588668728461'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/08/codigos-del-motor-de-informes-dinamicos.html' title='Códigos del motor de informes dinámicos en PDF'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-8408152235351424809</id><published>2009-06-27T17:43:00.001Z</published><updated>2009-06-27T17:43:06.215Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='gestor contenidos'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Sistema de plugins en C# usando Reflexión</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;En este post os voy a describir un pequeño sistema de plugins que implementé para un proyecto y que me resultó de mucha utilidad y sobre todo, me permitió aumentar el sistema sin tener que cambiar nada de lo ya establecido (códigos, recompilaciones, etc.).&lt;br/&gt;&lt;br/&gt;La idea es disponer de un &lt;font color='#999900'&gt;&lt;b&gt;sistema de plugins para un CMS&lt;/b&gt;&lt;/font&gt; (gestor de contenidos) de forma que cada plugin sea autogestionado y no haya que tocar nada del sistema a la hora de introducir un nuevo plugin, salvo lógicamente introducir su definición en base de datos. En el proyecto que implementé, los plugins eran elementos visuales que permitían realizar la maquetación de las páginas mostrando el contenido de base de datos de diferentes formas (contenido tabulado, histórico, contenido con scroll, publicidad, etc.).&lt;br/&gt;&lt;br/&gt;&lt;a href='http://lh5.ggpht.com/_uUP4eiIAPJ8/SkZYLW8hOuI/AAAAAAAAAdE/u5TchU4SWbc/%5BUNSET%5D.gif?imgmax=800'&gt;&lt;img height='' width='400' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/SkZYLW8hOuI/AAAAAAAAAdE/u5TchU4SWbc/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;No voy a entrar en cómo implementar toda la estructura del sistema de elementos visuales (será para un artículo posterior), lo importante es cómo podemos, acceder a clases de c# sin utilizar elementos tipados. Es decir, lo normal para instanciar un objeto es utilizar la siguiente nomenclatura:&lt;br/&gt;&lt;br/&gt;&lt;i&gt;&lt;b&gt;TipoObjeto miObjeto = new TipoObjeto(parametros);&lt;/b&gt;&lt;/i&gt;&lt;br/&gt;&lt;br/&gt;En el caso de un sistema dinámico de plugins, no podemos utilizar esa nomenclatura porque no sabemos a priori la clase del objeto a utilizar. En esta situación, la reflexión se nos ofrece como técnica perfecta.&lt;br/&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;&lt;br/&gt;Implementación del sistema de plugins&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Los plugins se dan de alta en base de datos, cada proyecto puede utilizar su propia definición de tablas. En mi caso, creé dos tablas, una para guardar la definición del elemento y otra para almacenar las propiedades modificables del elemento. Por ejemplo, uno de los plugins era para introducir un bloque de código HTML directamente en la página. La definición de este elemento es:&lt;br/&gt;&lt;a href='http://lh6.ggpht.com/_uUP4eiIAPJ8/SkZO1DhHvqI/AAAAAAAAAc0/KcPi1hCuEeY/%5BUNSET%5D.gif?imgmax=800'&gt;&lt;img height='' width='400' src='http://lh6.ggpht.com/_uUP4eiIAPJ8/SkZO1DhHvqI/AAAAAAAAAc0/KcPi1hCuEeY/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;y la definición de sus propiedades es:&lt;br/&gt;&lt;a href='http://lh3.ggpht.com/_uUP4eiIAPJ8/SkZPPnWmVII/AAAAAAAAAc4/Zg6WwJeOp-c/%5BUNSET%5D.gif?imgmax=800'&gt;&lt;img src='http://lh3.ggpht.com/_uUP4eiIAPJ8/SkZPPnWmVII/AAAAAAAAAc4/Zg6WwJeOp-c/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;'/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Lo importante de los datos almacenados para cada elemento es el campo &lt;font color='#339999'&gt;&lt;b&gt;"clase"&lt;/b&gt;&lt;/font&gt; en el que se guarda la clase de código que implementa la funcionalidad de este elemento. En este caso, la clase es &lt;b&gt;plugins.elementoHtml&lt;/b&gt;. Este campo se utiliza luego para la reflexión.&lt;br/&gt;&lt;br/&gt;&lt;font color='#cc6600'&gt;&lt;b&gt;Interfaz de los plugins&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;Este paso no es necesario pero es bueno que todas las clases que se encarguen de plugin implementen una interfaz obligando a que el método público de acceso sea siempre igual y no haya fallos de parámetros. En mi caso, la interfaz definía los siguientes métodos:&lt;br/&gt;&lt;a href='http://lh5.ggpht.com/_uUP4eiIAPJ8/SkZRHh3YwrI/AAAAAAAAAc8/PzqPHzXmSjE/%5BUNSET%5D.gif?imgmax=800'&gt;&lt;img height='' width='400' src='http://lh5.ggpht.com/_uUP4eiIAPJ8/SkZRHh3YwrI/AAAAAAAAAc8/PzqPHzXmSjE/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;/a&gt;&lt;br/&gt;La interfaz define dos métodos, uno para obtener el código html del plugin cuando se debe insertar en el centro de la página y otro para cuando se debe insertar en el lateral de la página. Los parámetros que se pasan son el id particular para cada elemento y un object extras con parámetros extras que hicieran falta en cada caso.&lt;br/&gt;&lt;font color='#cc6600'&gt;&lt;b&gt;&lt;br/&gt;El quid de la cuestión&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;En cada proyecto, obtendremos referencias a nuestros plugins de la manera que queramos. El quid de la cuestión se encuentra en las líneas que utilizan la reflexión para acceder a los métodos de la clase de cada plugin:&lt;br/&gt;&lt;a href='http://lh4.ggpht.com/_uUP4eiIAPJ8/SkZS0_LiyaI/AAAAAAAAAdA/2gArTzIlBds/%5BUNSET%5D.gif?imgmax=800'&gt;&lt;img height='' width='400' src='http://lh4.ggpht.com/_uUP4eiIAPJ8/SkZS0_LiyaI/AAAAAAAAAdA/2gArTzIlBds/%5BUNSET%5D.gif?imgmax=800' style='max-width: 800px;' title='' alt=''/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Lo que hacemos es:&lt;br/&gt;&lt;ol&gt;&lt;li&gt;Obtener el campo "clase" de la base de datos y llamar al método &lt;font color='#336666'&gt;&lt;b&gt;Type.GetType&lt;/b&gt;&lt;/font&gt; para obtener el tipo del elemento. &lt;br/&gt;&lt;/li&gt;&lt;li&gt;A través de reflexión podemos obtener acceso al constructor e invocarlo pasándole los argumentos necesarios, en este caso null porque no hay argumentos.&lt;/li&gt;&lt;li&gt;Obtener la información del método "Renderizar" que es el que utilizamos de cada clase y que define la interfaz.&lt;/li&gt;&lt;li&gt;Invocamos el método pasándole el objeto inicializado mediante el constructor y le pasamos un vector de objects con los parámetros que el método está esperando.&lt;/li&gt;&lt;li&gt;El resultado del método (en este caso un string), se obtiene haciendo un cast a string.&lt;br/&gt;&lt;/li&gt;&lt;/ol&gt;&lt;font color='#cc9933'&gt;&lt;b&gt;Conclusión&lt;/b&gt;&lt;/font&gt;&lt;br/&gt;La reflexión es una herramienta muy potente dentro del lenguaje .net que permite llamar a métodos y objetos sin conocer previamente el tipo. Esto permite generar sistemas como el descrito de una forma eficiente. El problema estriba en que, inicialmente no es un tipo de programación sencilla y requiere un tiempo para acostumbrarse a cómo funciona.&lt;br/&gt;&lt;br/&gt;Espero que os haya gustado este artículo y que os sirva esta idea para vuestros desarrollos. En mi caso, me ha sido de mucha utilidad.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-8408152235351424809?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/8408152235351424809/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=8408152235351424809' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8408152235351424809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8408152235351424809'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/06/sistema-de-plugins-en-c-usando.html' title='Sistema de plugins en C# usando Reflexión'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_uUP4eiIAPJ8/SkZYLW8hOuI/AAAAAAAAAdE/u5TchU4SWbc/s72-c/%5BUNSET%5D.gif?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-1979809829986417852</id><published>2009-06-14T17:17:00.002Z</published><updated>2009-06-14T17:22:46.222Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Problema de expiración de la sesión en ASP.net</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;Los códigos de este post los podéis descargar desde &lt;a href="http://www.nidea-soluciones.com/descargas/ControlSesion.rar"&gt;aquí&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finalmente, por fin he encontrado un rato para escribir un post en el blog. Tenía en mente varios temas pero al fin me he decidido por éste que me parece bastante interesante y útil para aquellos que desarollamos &lt;span style="color:#ff9900;"&gt;&lt;b&gt;aplicaciones en asp.net&lt;/b&gt;&lt;/span&gt;. Pongámonos en situación, cuando escribimos aplicaciones, una de las herramientas más utilizadas para mantener la persistencia de los datos es la sesión, almacenamos en sesión tablas con las que trabaja el usuario por pantalla, ids de filas, usuarios, variables, etc. todo ello para que cuando el usuario pulse algún botón y se realice un postback, podamos realizar las acciones correspondientes. Es decir, la sesión &lt;span style="color:#cc6600;"&gt;&lt;b&gt;nos mantiene conectado con el usuario en un entorno desconectado&lt;/b&gt;&lt;/span&gt;. El problema viene cuando el tiempo de sesión expira, si el usuario no ha realizado ninguna acción &lt;span style="color:#006600;"&gt;&lt;b&gt;pasados x minutos (5 por defecto)&lt;/b&gt;&lt;/span&gt;, el servidor (IIS) elimina su sesión. En el momento en que el usuario pulse un botón y se vaya al servidor, nos encontraremos con que aquellos datos que habíamos guardado en la sesión ya no existen y (dependiendo de cómo controlemos esta situación) saltará una excepción en algún punto de nuestro código, echándonos fuera de la aplicación, o saltando una fantástica pantalla amarilla o algo parecido.&lt;br /&gt;&lt;br /&gt;En aplicaciones en las que las operaciones se realicen en el servidor no vamos a tener problemas con la sesión porque cada vez que el usuario realice un postback, la cuenta de &lt;span style="color:#339999;"&gt;&lt;b&gt;expiración de la sesión se reinicirá&lt;/b&gt;&lt;/span&gt;. En el caso que hagamos aplicaciones que hagan uso de la lógica del cliente, tipo blogs, editores wysiwyg, o que el usuario realice &lt;span style="color:#996633;"&gt;&lt;b&gt;operaciones largas en el explorador sin tener que ir al servidor&lt;/b&gt;&lt;/span&gt;, el tiempo de expiración de la sesión se convierte en un gran problema para el programador y en una gran molestia para el cliente. Imaginaos escribiendo un post en un blog y que cuando lleváis 30 minutos escribiendo, habéis acabado el post le dais a guardar y salta una excepción, perdiendo todo el trabajo...&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#999900;"&gt;&lt;b&gt;Posibles soluciones a este problema&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Existen varias soluciones a este problema, que dependiendo de dónde esté alojada nuestra aplicación nos serán factibles o no.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;Solución 1: Web.config&lt;/b&gt;&lt;br /&gt;La solución más fácil es incorporar en nuestro web.config la etiqueta "&lt;b&gt;sessionState&lt;/b&gt;" con el atributo "&lt;b&gt;timeout&lt;/b&gt;" indicándole el número de minutos que deseamos que se mantenga la sesión (dentro de la sección &lt;b&gt;system.web&lt;/b&gt;):&lt;br /&gt;&lt;br /&gt;&lt;img src="http://lh4.ggpht.com/_uUP4eiIAPJ8/SjTGFMH7zmI/AAAAAAAAAcM/wC10yDUClxw/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="386" height="38" /&gt;&lt;br /&gt;&lt;br /&gt;En este caso, hemos aumentado el tiempo de sesión a 60 minutos, antes de que el servidor la elimine. Sin embargo, me he encontrado alojamientos en los que, aunque en mi web.config tenga incluido este tag, el tiempo de sesión &lt;span style="color:#cc9933;"&gt;&lt;b&gt;viene marcado por el servidor&lt;/b&gt;&lt;/span&gt; sin posibilidad de cambiarlo desde aquí.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solución 2: Pool de aplicaciones&lt;/b&gt;&lt;br /&gt;La segunda solución con la que contamos es la de crear un &lt;span style="color:#999900;"&gt;&lt;b&gt;pool de aplicaciones en el IIS para nuestra aplicación&lt;/b&gt;&lt;/span&gt;. En dicho pool podemos especificarle el tiempo de sesión que queremos. Además, al crear un pool propio, se lanza un proceso en el sistema para nosotros solos. Esto es bueno en el caso de alojamientos compartidos en los que en el mismo proceso puede haber muchas aplicaciones ejecutándose. Siempre es aconsejable tener nuestro propio pool de aplicaciones, el cual se crea de la siguiente manera:&lt;br /&gt;&lt;br /&gt;1. Desde el administrador de IIS, pulsamos con el botón derecho sobre "Grupos de aplicaciones" y seleccionamos un nuevo grupo:&lt;br /&gt;&lt;img src="http://lh3.ggpht.com/_uUP4eiIAPJ8/SjUji3IeHFI/AAAAAAAAAcQ/0upeoDc4TwI/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;br /&gt;2. Le damos un nombre al nuevo grupo de aplicaciones:&lt;br /&gt;&lt;img src="http://lh5.ggpht.com/_uUP4eiIAPJ8/SjUjyyeMz9I/AAAAAAAAAcU/Su1xtLA3l7s/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;br /&gt;3. Lo siguiente es configurar las opciones de rendimiento para este grupo de aplicaciones, como la cantidad de memoria a asignar, el tiempo de reciclado del proceso o el tiempo de sesión para este grupo, entre otras opciones:&lt;br /&gt;&lt;img src="http://lh5.ggpht.com/_uUP4eiIAPJ8/SjUkHIe3OBI/AAAAAAAAAcY/W5AIii6q7-Y/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;br /&gt;4. Por último, a un sitio o directorio web, le asignaremos este grupo de aplicaciones desde sus propiedades:&lt;br /&gt;&lt;img src="http://lh4.ggpht.com/_uUP4eiIAPJ8/SjUkZNYW7FI/AAAAAAAAAcc/wr07I-knkmM/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#666600;"&gt;&lt;b&gt;Solución 3: Servicio web de Echo&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Para implementar las dos soluciones anteriores necesitamos tener control sobre el servidor (cosa que no siempre es así). En el caso que tengamos alojamientos compartidos, podemos utilizar esta opción (es la que utilizo ahora). Normalmente, un portal web dispone de dos partes, la pública (en la que normalmente se puede funcionar con cookies) y la privada en la que trabajaremos con sesiones. Es en la parte privada donde utilizaremos esta opción. La idea es implementar un servicio web que &lt;span style="color:#333399;"&gt;&lt;b&gt;simplemente realice un eco&lt;/b&gt;&lt;/span&gt;, reciba un parámetro y lo devuelva. Habilitamos la sesión para el servicio web con lo que cada vez que se llame a este servicio, la cuenta de expiración de la sesión se reinicirá. Desde las página de gestión&lt;span style="color:#663333;"&gt;&lt;b&gt; se llama, vía AJAX&lt;/b&gt;&lt;/span&gt;, periódicamente (yo lo tengo cada 50 segundos) a dicho servicio web para que no reinicie la cuenta. De forma esquemática, la solución es la siguiente:&lt;br /&gt;&lt;img src="http://lh3.ggpht.com/_uUP4eiIAPJ8/SjUoRrXfDpI/AAAAAAAAAcg/E0Fhi2n0ESE/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="444" height="164" /&gt;&lt;br /&gt;&lt;br /&gt;El código del servicio web es el siguiente:&lt;br /&gt;&lt;img src="http://lh3.ggpht.com/_uUP4eiIAPJ8/SjUpbuP3w9I/AAAAAAAAAck/y0tkwNxX8Vw/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="436" height="403" /&gt;&lt;br /&gt;Tenemos que introducir el &lt;span style="color:#996633;"&gt;&lt;b&gt;using System.Web.Script.Services&lt;/b&gt;&lt;/span&gt; para poder utilizar este servicio web vía AJAX. Además, la definición del servicio web incluye la sentencia&lt;span style="color:#336666;"&gt;&lt;b&gt; [WebMethod(true)] &lt;/b&gt;&lt;/span&gt;indicando que se utilizará la sesión en ese método del servicio web. Para llamar a dicho método desde la página maestra (lo normal) o desde cualquier página de nuestra aplicación utilizaremos el siguiente código:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;a. Incluir una referencia web al servicio web creado.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;b. Dar de alta el servicio web mediante el ScriptManager de la página&lt;/b&gt;&lt;br /&gt;En la propiedad Path pondremos la ubicación del fichero .asmx (servicio web). Si, al crear el servicio web, separados el código del fichero, se creará un fichero .asmx con la definición del servicio web donde le hayamos dicho y un fichero .cs con los códigos dentro de la carpeta App_Code.&lt;br /&gt;&lt;img src="http://lh6.ggpht.com/_uUP4eiIAPJ8/SjUqnvYub3I/AAAAAAAAAco/TUyXzwtSO3U/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="501" height="59" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;c. Crear la función Javascript que llama al servicio web&lt;/b&gt;&lt;br /&gt;&lt;img src="http://lh5.ggpht.com/_uUP4eiIAPJ8/SjUrjZ_Of5I/AAAAAAAAAcs/XesSx9eV3NQ/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="345" height="103" /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;d. Crear el temporizador para que se repita la llamada cada x segundos&lt;/b&gt;&lt;br /&gt;Ponemos la función en el onload de la página para que se ejecute al iniciar la página. En este caso esta puesto que se repita la llamada cada 50 segundos (50.000 milisegundos)&lt;br /&gt;&lt;img src="http://lh6.ggpht.com/_uUP4eiIAPJ8/SjUr60BFosI/AAAAAAAAAcw/kq_e_BH4U3w/%5BUNSET%5D.gif?imgmax=800" style="max-width: 800px;" width="353" height="15" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#666600;"&gt;&lt;b&gt;Conclusión&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Esta última es una solución sencilla que nos puede servir en cualquier entorno en el que trabajemos con aplicaciones asp.net. Utilizando el servicio de echo, nos aseguramos que &lt;span style="color:#336666;"&gt;&lt;b&gt;la sesión del usuario no va a expirar&lt;/b&gt;&lt;/span&gt; independientemente del tiempo que esté sin hacer ningún postback. En el caso que el usuario cierre la ventana del explorador, se deja de llamar al servicio con lo que la sesión expirará en los 5 minutos correspondientes. Por supuesto, siempre podemos colocar el botón de cerrar que matará la sesión. Como siempre, espero que os sea de utilidad este post y gracias por leer este blog (ya sois un montón).&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-1979809829986417852?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/1979809829986417852/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=1979809829986417852' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1979809829986417852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1979809829986417852'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/06/problema-de-expiracion-de-la-sesion-en.html' title='Problema de expiración de la sesión en ASP.net'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_uUP4eiIAPJ8/SjTGFMH7zmI/AAAAAAAAAcM/wC10yDUClxw/s72-c/%5BUNSET%5D.gif?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-1365914587144841518</id><published>2009-04-07T17:01:00.013Z</published><updated>2009-04-07T17:49:33.887Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='gestor contenidos'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Traductor de Artilugios en ASP.NET</title><content type='html'>&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;blockquote&gt;La página de demostración la podéis encontrar &lt;a href="http://demos.formacionsantaana.com/Default.aspx"&gt;aquí.&lt;/a&gt;&lt;br /&gt;El comprimido con los códigos del proyecto os lo podéis descargar de &lt;a href="http://www.nidea-soluciones.com/descargas/PruebaTraductor.rar"&gt;aquí&lt;/a&gt;.&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;Hacía tiempo que no escribía un post pero, finalmente, he conseguido un poco de tiempo. En este post lo que os voy a contar es un pequeño pero muy útil, por lo menos para mí, proyecto que hice en su día y que voy mejorando y modificando a medida que lo necesito. El proyecto se llama &lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(204,153,51)"&gt;"Traductor de Artilugios"&lt;/span&gt;&lt;/span&gt; (un nombre raro, pero es que no tenía y se lo acabo de poner) y es un generador de objetos complejos para gestores de contenido.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(0,153,0)"&gt;Un generador de qué?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;La idea la cogí de Wordpress, el cual permite introducir ciertos sinónimos en el editor de post que posteriormente son traducidos a un html más complejo (video y música). Es una forma muy sencilla de poder introducir componentes flash que precisan de etiquetas object o embed o código html elaborado.&lt;br /&gt;&lt;br /&gt;Con esta idea me hice una &lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(204,102,0)"&gt;pequeña clase TraductorObjetos.cs&lt;/span&gt;&lt;/span&gt; que generaba ese código en las páginas de forma dinámica. Inicialmente lo hice para &lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(153,153,0)"&gt;video flash&lt;/span&gt;&lt;/span&gt; (flv en el servidor) y &lt;span class="Apple-style-span" style="COLOR: rgb(102,102,0)"&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;videos de youtube&lt;/span&gt;&lt;/span&gt;, luego le metí un &lt;span class="Apple-style-span" style="COLOR: rgb(153,153,0)"&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;reproductor mp3&lt;/span&gt;&lt;/span&gt;, &lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(153,153,0)"&gt;galeria javascript, ventanas modales, galeria flash&lt;/span&gt;&lt;/span&gt;. A medida que voy necesitando algo lo voy metiendo.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(0,153,0)"&gt;Sí, muy bien, pero ¿cómo funciona?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;El funcionamiento es el siguiente:&lt;/p&gt;&lt;p&gt;a. Desde un editor WYSIWYG (yo utilizo FCKEditor) se introduce el texto de la entrada y se incluye el sinónimo del artilugio. En este caso, voy a meter un video flash por lo que utilizo el sinónimo &lt;span class="Apple-style-span" style="FONT-WEIGHT: bold"&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(204,102,0)"&gt;video. &lt;/span&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: normal"&gt;La cadena que utilizo es &lt;/span&gt;&lt;span class="Apple-style-span" style="COLOR: rgb(204,102,0)"&gt;@video [urlVideo]=[Yeguada1.flv]@&lt;/span&gt;&lt;span class="Apple-style-span" style="FONT-WEIGHT: normal"&gt; indicando que la url donde se encuentra el video es yeguada1.flv.&lt;/span&gt;&lt;/span&gt; &lt;/p&gt;&lt;p align="left"&gt;&lt;a href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SduMi2E_E_I/AAAAAAAAAbY/RG0skrPnGCM/s1600-h/artilugios2.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5322001914928239602" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 104px" alt="" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SduMi2E_E_I/AAAAAAAAAbY/RG0skrPnGCM/s400/artilugios2.gif" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;b. Ese código se guarda en base de datos. A la hora de renderizar el código en pantalla, se llama a la función &lt;strong&gt;&lt;span style="color:#336666;"&gt;Traducir&lt;/span&gt;&lt;/strong&gt; de la clase TraductorObjetos.cs para que &lt;span style="color:#999900;"&gt;&lt;strong&gt;rastree el código HTML&lt;/strong&gt;&lt;/span&gt; guardado en base de datos en busca de artilugios. La definición de los artilugios se &lt;strong&gt;&lt;span style="color:#339999;"&gt;guarda en una tabla de base de datos&lt;/span&gt;&lt;/strong&gt; con dos campo (nombre y código).&lt;a href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SduON3u1f-I/AAAAAAAAAbw/3xQt2s42jFs/s1600-h/artilugios3.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5322003753618210786" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 32px" alt="" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SduON3u1f-I/AAAAAAAAAbw/3xQt2s42jFs/s400/artilugios3.gif" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;c. Una vez localizado el sinónimo en la cadena de HTML, se sustituye dicha cadena por el valor de base de datos, poniendo los parámetros en su lugar correspondiente. Los parámetros en base de datos se identifican por el símbolo @ (p.e. @urlVideo es un parámetro que será sustituido en tiempo de ejecución).&lt;/p&gt;&lt;p&gt;d. Finalmente, se devuelve el código traducido para que sea renderizado en pantalla.&lt;/p&gt;&lt;a href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SduPWGWvzjI/AAAAAAAAAb4/tcxmeK1BDWQ/s1600-h/artilugios4.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5322004994494287410" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 221px" alt="" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SduPWGWvzjI/AAAAAAAAAb4/tcxmeK1BDWQ/s400/artilugios4.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;Extensibilidad&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Es muy fácil incluir más elementos en el proyecto, basta con insertar el código a traducir en la tabla con los parámetros correspondientes y listo. Tened en cuenta que todos los ficheros extras utilizados (javascript, flash, hojas de estilo,...) por lo artilugios se localizan en la carpeta "extras" y se deben cargar en la página para que funcionen correctamente.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#009900;"&gt;Conclusión&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Espero que este proyecto os sirva tanto como me sirve a mi en mis desarrollos. Con &lt;strong&gt;&lt;span style="color:#ff6600;"&gt;una simple línea, el usuario es capaz de generar códigos muy complejos&lt;/span&gt;&lt;/strong&gt; que de otra forma no podría hacerlo. Os he dejado los códigos del proyecto así como una página de demo donde podéis probar con las diferentes cadenas de sinónimos que tengo puestas.&lt;/p&gt;&lt;a href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SduRI1Y1x0I/AAAAAAAAAcA/bm12YVOxkas/s1600-h/artilugios5.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5322006965624620866" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 217px" alt="" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SduRI1Y1x0I/AAAAAAAAAcA/bm12YVOxkas/s400/artilugios5.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&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/37408564-1365914587144841518?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/1365914587144841518/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=1365914587144841518' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1365914587144841518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1365914587144841518'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/04/traductor-de-artilugios-en-aspnet.html' title='Traductor de Artilugios en ASP.NET'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_uUP4eiIAPJ8/SduMi2E_E_I/AAAAAAAAAbY/RG0skrPnGCM/s72-c/artilugios2.gif' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-5757726305643864153</id><published>2009-03-02T11:37:00.004Z</published><updated>2009-03-02T11:45:21.086Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='revista'/><category scheme='http://www.blogger.com/atom/ns#' term='artículo'/><title type='text'>Artículo en la revista "Solo Programadores"</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SavGM1fY46I/AAAAAAAAAa4/YYXiCj8SWXA/s1600-h/soloP1.gif"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 170px; height: 227px;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SavGM1fY46I/AAAAAAAAAa4/YYXiCj8SWXA/s400/soloP1.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5308554509605725090" /&gt;&lt;/a&gt;&lt;br /&gt;Este mes &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;he publicado un artículo&lt;/span&gt;&lt;/span&gt; en la revista "&lt;a href="http://www.revistasprofesionales.com/principal.php?id_revista=23"&gt;Solo Programadores&lt;/a&gt;". El artículo se titulo "Aplicaciones multiidioma en ASP.NET" e invito a todo el mundo a que lo lea. Es la primera vez que publico en una &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 153, 0);"&gt;revista tecnológica de tirada nacional&lt;/span&gt;&lt;/span&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;El sumario de la revista es el siguiente:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SavGfI2UX6I/AAAAAAAAAbA/JjhODTQULy4/s400/soloP2.gif" style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 300px; height: 400px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5308554824039817122" /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-5757726305643864153?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/5757726305643864153/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=5757726305643864153' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5757726305643864153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5757726305643864153'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/03/articulo-en-la-revista-solo.html' title='Artículo en la revista &quot;Solo Programadores&quot;'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_uUP4eiIAPJ8/SavGM1fY46I/AAAAAAAAAa4/YYXiCj8SWXA/s72-c/soloP1.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-8323615469507204003</id><published>2009-02-23T11:47:00.000Z</published><updated>2009-02-23T17:59:50.266Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='Rijndael'/><category scheme='http://www.blogger.com/atom/ns#' term='encriptación'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Encriptación de imágenes/ficheros en servidor con asp.net</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SaLhNk9S1EI/AAAAAAAAAaY/nNxmkHFxVnI/s1600-h/rijndael6.gif"&gt;&lt;/a&gt;Las clases Crypto.cs y CryptoProvider.cs las podéis descargar desde &lt;a href="http://www.nidea-soluciones.com/descargas/Crypto.rar"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SaLgEbds5RI/AAAAAAAAAaQ/Uf2ba2UcEOM/s1600-h/rijndael5.gif"&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLe5hF8L7I/AAAAAAAAAaI/r95w6bu9Wfo/s1600-h/rijndael4.gif"&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLb1mwYccI/AAAAAAAAAaA/Fep3Ry031yg/s1600-h/rijndael3.gif"&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLaYMPalkI/AAAAAAAAAZ4/6BIoe9Y-CfA/s1600-h/rijndael2.gif"&gt;&lt;/a&gt;&lt;br /&gt;En este artículo vamos a explorar un aspecto que siempre me ha tenido preocupado a la hora de trabajar con imágenes o ficheros subidos por los usuarios en aplicaciones en internet con asp.net. El problema es la encriptación de esos archivos para evitar que alguna persona pueda linkarlos y acceder a ellos. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 153, 0);"&gt;La raiz del problema&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Cuando programamos una aplicación ASP.NET para que se puedan subir archivos a una carpeta, debemos darle permiso al usuario con el que se ejecuta el proceso ASP.NET para que escriba en esa carpeta y para leer la información (para su poste&lt;/div&gt;&lt;div&gt;rior visionado). Una alternativa es realizar un impersonate sobre el proceso (algo que nunca me ha gustado). Otras alternativas que propone la gente es darles nombres extraños, ubicaciones extrañas, etc. pero no dejan de ser soluciones de ocultación que no solventan el problema. La alternativa que vamos a ver en este post es la de realizar una &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;encriptación del fichero subido con el algoritmo AES-Rijndael&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 204, 51);"&gt; &lt;/span&gt;&lt;/span&gt;de forma que aunque un potencial usuario malintencionado gane acceso al fichero subido, no sea capaz de averiguar su contenido.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 153, 0);"&gt;Las dos partes del problema&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;La encriptación de ficheros en servidor tiene dos partes bien diferenciadas que tenemos que solventar:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Encriptación al subir el fichero&lt;/li&gt;&lt;li&gt;Desencriptación al vuelo al visionar/descargar el fichero sin dejar ninguna copia desencriptada en el servidor.&lt;/li&gt;&lt;/ol&gt;El flujo de información del proyecto es el siguiente:&lt;/div&gt;&lt;div&gt;&lt;img src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SaLYcUK8N9I/AAAAAAAAAZw/A6RYHFJg-vg/s400/rijndael1.gif" style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 256px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5306041291958400978" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 153, 0);"&gt;Vamos al lío, subiendo archivos al servidor...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;La primera parte es subir archivos al servidor. Cada uno utilizará el método que quiera, yo he utilizado el componente FileUpload que viene con los controles de servidor. Cuando se pulsa el botón de subir el archivo, se ejecuta el siguiente código, en el que se realizan las siguientes acciones:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Se comprueba que la extensión sea pdf&lt;/li&gt;&lt;li&gt;Se comprueba que el tamaño no exceda los 10MB (estoy hay que configurarlo en el web.config para que el servidor lo admita)&lt;/li&gt;&lt;li&gt;Se sube el fichero con un nuevo nombre único&lt;/li&gt;&lt;li&gt;Se encripta el fichero&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); "&gt;&lt;img src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLaYMPalkI/AAAAAAAAAZ4/6BIoe9Y-CfA/s400/rijndael2.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5306043420133463618" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 400px; height: 258px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;La línea clave es &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;objencriptador.EncriptarFichero()&lt;/span&gt;&lt;/span&gt;, ¿qué es lo que hace esta función? Esta función es la encargada de encriptar el fichero pasado en el primer parámetro, guardarlo con el nombre del segundo parámetro y eliminar el original.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); "&gt;&lt;img src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLb1mwYccI/AAAAAAAAAaA/Fep3Ry031yg/s400/rijndael3.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5306045024978891202" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 400px; height: 316px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Este método se encuentra en una clase llamada Crypto.cs que utiliza otra llamada CryptoProvider.cs que se encarga de inicializar el proveedor de encriptación. Hay que tener en cuenta que el algoritmo Rijndael se basa en dos cadenas: &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;la clave y el vector&lt;/span&gt;&lt;/span&gt; de inicialización. Ambos valores se guardan en el &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;app.config de la clase de negocio o se codifican en la clase&lt;/span&gt;&lt;/span&gt;. Al inicializar el proveedor Rijndael, ambos valores son pasados a su constructor para que pueda encriptar y desencriptar.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;En este método, lo que se hace es abrir dos streams, uno para la entrada y otro para la salida. Seguidamente se inicializa el proveedor de servicios de encriptación con la clave (Key) y el vector de inicialización (IV), en modo encriptación. Una vez inicializado, el siguiente paso es crear un stream encriptado para ir pasando del fichero de origen al destino. Pasamos la información de un fichero a otro a través del CryptoStream, cerramos todos los flujos y eliminamos el fichero original.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 153, 0);"&gt;Ya está encriptado, ¿cómo lo ve el usuario?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Ya tenemos el fichero encriptado en el servidor, por lo que el siguiente paso será desencriptarlo cuando haya que hacerlo sin dejar copia en el servidor. Para ello nos vamos a crear una página aspx que devuelva un &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;flujo desencriptado&lt;/span&gt;&lt;/span&gt; al explorador del usuario.&lt;/div&gt;&lt;div&gt;&lt;img src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SaLe5hF8L7I/AAAAAAAAAaI/r95w6bu9Wfo/s400/rijndael4.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5306048390713061298" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 400px; height: 146px; " /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;En el momento que queramos descargar/visualizar el fichero desencriptado, la página en la que nos encontremos invocará a la página &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;ObtenerPDF.aspx&lt;/span&gt;&lt;/span&gt; que solicitará el fichero desencriptado a la clase Crypto.cs. Esta clase, devolverá un &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;MemoryStream desencriptado&lt;/span&gt;&lt;/span&gt; que será devuelto al explorador del cliente (junto con las cabeceras necesarias) para que sea renderizado en pantalla.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;img src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SaLgEbds5RI/AAAAAAAAAaQ/Uf2ba2UcEOM/s400/rijndael5.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5306049677692298514" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 400px; height: 236px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;En mi caso, miro el fichero a desencriptar de la sesión del usuario. Habría que comprobar la seguridad para evitar accesos indebidos. Una vez obtenido el fichero, invocamos al método &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;DesencriptarFichero() &lt;/span&gt;&lt;/span&gt;de la clase Crypto, que devuelve un objeto del tipo &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 153, 51);"&gt;MemoryStream&lt;/span&gt;&lt;/span&gt;. Ese objeto es devuelto en el Response de la página para que el cliente lo muestre en pantalla.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;El método DesencriptarFichero realiza las operaciones inversas que se realizaron en el método de encriptación.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); "&gt;&lt;img src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SaLhNk9S1EI/AAAAAAAAAaY/nNxmkHFxVnI/s400/rijndael6.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5306050934371177538" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 400px; height: 342px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Con esto tenemos ya listo nuestro sistema de encriptación/desencriptación de ficheros en servidor. Tened en cuenta que esta solución es para entornos de hosting remoto en los que no tenemos capacidad de tocar el sistema de archivos. Si el servidor es nuestro, existen otras alternativas como la reubicación en carpetas fuera del directorio web, u otras.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 153, 0);"&gt;Conclusión&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Como siempre, espero que os haya interesado este post. En este caso, el código que he puesto es solamente el de las clases Crypto y CryptoProvider. Cada caso es particular así que cada uno adaptará la solución a su entorno. En este artículo he intentado dar unas guías para que podáis de una forma "fácil" incluir la encriptación en vuestros desarrollos asp.net.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-8323615469507204003?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/8323615469507204003/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=8323615469507204003' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8323615469507204003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8323615469507204003'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2009/02/encriptacion-de-imagenesficheros-en.html' title='Encriptación de imágenes/ficheros en servidor con asp.net'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_uUP4eiIAPJ8/SaLYcUK8N9I/AAAAAAAAAZw/A6RYHFJg-vg/s72-c/rijndael1.gif' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-4082820931131235367</id><published>2008-12-08T12:00:00.014Z</published><updated>2008-12-08T16:11:41.739Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='EHAS'/><category scheme='http://www.blogger.com/atom/ns#' term='telecomunicaciones rurales'/><category scheme='http://www.blogger.com/atom/ns#' term='redes inalámbricas'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Diseño de redes inalámbricas con Radio Mobile (III)</title><content type='html'>Bueno, lo primero, mil perdones por tardar tantísimo en seguir escribiendo. Un pico de trabajo...que más bien se podría decir que ha sido una meseta de trabajo, me ha tenido ocupado durante muchísimo tiempo. En otra entrada explicaré tranquilamente en qué (QoS en enlaces WiFi de largo alcance sobre empotrados con GNU/Linux y driver madwifi). Pero ahora vamos a lo que nos ocupaba, ¡al turrón!&lt;br /&gt;&lt;br /&gt;En las anteriores entradas (&lt;a href="http://nidea-soluciones.blogspot.com/2008/05/diseo-de-redes-inalmbricas-con-radio.html"&gt;I&lt;/a&gt; y &lt;a href="http://nidea-soluciones.blogspot.com/2008/05/diseo-de-redes-inalmbricas-con-radio_27.html"&gt;II&lt;/a&gt;), vimos cómo instalar una máquina virtual sobre una Ubuntu, en la que introdujimos un Windows XP, y que optimizamos para permitirnos instalar nuestro software Radio Mobile. Aprendimos también a descargarnos los mapas SRTM de la región sobre la que queremos diseñar nuestras redes inalámbricas y utilizarlos con Radio Mobile. Hoy trataremos de simular un enlace WiFi de largo alcance y comprobar qué calidad de señal obtendríamos de montar físicamente la red. Es cierto que en este caso jugamos con ventaja, pues &lt;a href="http://cooperantesuc3m.blogspot.com/"&gt;la red ya está montada&lt;/a&gt; y está claro que funciona, pero aún así, descubriremos en el transcurso de la entrada que en nuestro diseño puede haber errores, y que el diseño no es único, probablemente a cada uno de vosotros os pudiera salir un diseño diferente y puedar ser todos buenos. La selección final vendrá dada también por las condiciones reales que no son emulables con nuestro software (ubicación de las poblaciones, posibilidad de acceso para instalación de repetidores, propiedad colectiva del terreno, negativa de la comunidad...y tantas otras posibilidades que pudieran ser determinantes fuera de lo que es el diseño puro y duro).&lt;br /&gt;&lt;br /&gt;Como ya dijimos, vamos a centrar el mapa en un punto de nuestra red que esté situado más o menos a la mitad, para así poder tener una perspectiva de toda nuestra red cuando esté completada. Yo he escogido el Puesto de Salud de Rumi Tuni, así a ojo, cuyas coordenadas son 74º 42' 21.8''O - 1º 47' 39.7''S. Para hacerlo, pinchamos en "Archivo -&gt; Propiedades del mapa", y ahí pulsamos en "Ingresar LAT LON o QRA". Introducimos las coordenadas. Pulsamos sobre la "N" para cambiarla a "S", es decir, en nuestro caso hablaremos de latitud sur, y dejamos la "O" como está pues queremos ingresar una longitud Oeste. Después de introducir las coordenadas, decimos "OK". Ahora introducimos una resolución de 2000 x 2000 pixeles y de altura unos 150 km, aunque ya veremos luego que con ésto no alcanzaremos a cubrir toda la red, pero nos sirve para poder ver la parte central de la red que será la que empecemos diseñando.&lt;br /&gt;&lt;br /&gt;Ahora pulsamos "Extraer", y nos debería salir un mapa como éste:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SEHFAnDk1lI/AAAAAAAAAX0/cto_7oGiK84/s1600-h/creando_mapa1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SEHFAnDk1lI/AAAAAAAAAX0/cto_7oGiK84/s320/creando_mapa1.png" alt="" id="BLOGGER_PHOTO_ID_5206659258491655762" border="0" /&gt;&lt;/a&gt;Lo que estáis viendo es el río Napo, al que podéis ver que se le une en la esquina inferior derecha un pequeño afluente que zigzaguea desde muy lejos, ese es el río Curaray, en cuya confluencia con el Napo se encuentra uno de los puntos de la red (San Rafael). El resto de los puntos están en el Napo. Aquí hay que decir que en la realidad, Curaray arriba y muy lejos del resto de la red hay otro punto pero que no está conectado con tecnología WiFi, sino con VHF, y por eso no lo veremos aquí. Si os interesa tener más información de cómo EHAS comunica vía VHF los puntos más aislados, podéis escribirme al correo o buscar vosotros mismos la información en &lt;a href="http://www.ehas.org/"&gt;la página de EHAS&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Antes de crear un nodo cliente de la red, vamos a crear las redes y lo que en Radio Mobile se llama "Sistema", que son las propiedades que afectarán a los nodos en general. Para proceder con más limpieza, tenemos que diferenciar entre dos tipos de enlaces, los "Enlaces de distribución", que en la práctica serán los enlaces de los centros y puestos de salud de la región hacia sus torres repetidoras, y los "Enlaces troncales", que serán los enlaces entre las torres con antenas directivas que trasladen los datos entre la red a través de la selva. Para hacernos una idea más real, aquí pongo una foto de una estación cliente típica vista desde su torre y de la parte alta de una estación repetidora (en este caso las fotos son del P.S. de Tempestad, para que le pongáis cara a lo que estáis diseñando).&lt;br /&gt;Estación cliente (la construcción con el techo verde):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SEHJOXDk1mI/AAAAAAAAAX8/Y6_mNwxlurI/s1600-h/_MG_1283.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SEHJOXDk1mI/AAAAAAAAAX8/Y6_mNwxlurI/s320/_MG_1283.JPG" alt="" id="BLOGGER_PHOTO_ID_5206663892761368162" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Estación repetidora:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SEHKlnDk1nI/AAAAAAAAAYE/nQ9HPdAiWUI/s1600-h/_MG_1249.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SEHKlnDk1nI/AAAAAAAAAYE/nQ9HPdAiWUI/s320/_MG_1249.JPG" alt="" id="BLOGGER_PHOTO_ID_5206665391704954482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Enlace de distribución entre estación cliente y estación repetidora (se puede ver la antena cliente apuntando a la parte alta de la torre, donde está la antena del repetidor apuntando hacia el cliente):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SEHLTXDk1oI/AAAAAAAAAYM/Z2ltQ81AbcI/s1600-h/_MG_1298.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SEHLTXDk1oI/AAAAAAAAAYM/Z2ltQ81AbcI/s320/_MG_1298.JPG" alt="" id="BLOGGER_PHOTO_ID_5206666177683969666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Pues bien, como os imaginaréis, Radio Mobile tiene que tener parametrizadas las antenas que vamos a usar para poder simular los enlaces. El software por defecto trae ya algunas antenas, pero para nuestro caso vamos a usar otras, por lo que necesitaremos de los ficheros *.ant correspondientes a las antenas que queramos probar en nuestros enlaces. En esta red se han usado antenas tipo yagi de 9dBi diseñadas para 2,4GHz para los enlaces entre cliente y repetidor y antenas de grilla de 24dBi que trabajan en la misma frecuencia, pero podéis probar con otras antenas e incluso simular los enlaces en otras frecuencias (para WiFi podéis probar en 5,2 o 5,8GHz que son los otros rangos de frecuencias permitidos) y ver si sería posible establecer los enlaces. Los enlaces en altas frecuencias sufren más atenuación que en bajas frecuencias, y actualmente los drivers inalámbricos para tarjetas que trabajan en esas frecuencias no son del todo estables para largas distancias en linux, pero si queréis probar, ésto es software, haced cuanto os plazca.&lt;br /&gt;&lt;br /&gt;En la sección de descargas públicas de la &lt;a href="http://isf.uc3m.es/web"&gt;página web de la delegación Carlos III de Ingeniería Sin Fronteras&lt;/a&gt;, tenemos unos cuantos de estos ficheros, así que si queréis, &lt;a href="http://isf.uc3m.es/descargas_publicas/Ficheros/antenas_radiomobile/"&gt;podéis descargarlos&lt;/a&gt;. Luego los introducís en la carpeta "antenna" de vuestro Radio Mobile (típicamente C:\Radio_Mobile\antenna) y ya podréis usar estas antenas en el programa. Si analizáis el fichero de una antena, veréis que no es muy complejo, es un simple fichero de texto que almacena el diagrama de radiación de la antena escribiendo las ganancias con respecto al azimut y a la elevación haciendo mediciones cada 10º de separación, así que si os habéis fabricado una antena de forma casera y podéis medir su ganancia, ya sabéis que podríais crearos vuestro fichero .ant de la antena personalizada.&lt;br /&gt;&lt;br /&gt;Antes de continuar, vamos a terminar de introducir todas las coordenadas de las unidades de nuestras redes. Me he dado cuenta de que en la entrada anterior os puse las coordenadas de las torres repetidoras de cada lugar, pero no de los centros y puestos de salud a los que dan servicio, así que vamos a hacer eso. Os pongo las coordenadas de todas las unidades:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cabo Pantoja (Torre):&lt;/span&gt; 0º58'13,26''S  75º10'29,21''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Torres Causana &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º6'16,53''S  75º0'14,17''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tempestad &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º17'22,81''S  74º52'27,42''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tupac Amaru &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º21'46,55''S  74º44'42,89''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Angoteros &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º34'9,54''S  74º36'20,17''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Campo Serio &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º47'35,48''S  74º42'50,09''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Rumi Tuni &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º3'16,22''S  74º26'9,30''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; San Rafael &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º22'1,43''S  74º6'42,91''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Copal Urco &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º20'23,41''S  73º47'26,23''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Santa Clotilde &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º29'22,07''S  73º40'41,02''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tacsha Curaray &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º48'47,46''S  73º32'27,30''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cabo Pantoja &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(CS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 0º58'13,70''S  75º10'29,20''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Torres Causana &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º6'16,61''S  75º0'14,48''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tempestad &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º17'21,28''S  74º52'28,94''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tupac Amaru &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º21'46,59''S  74º44'40,85''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Angoteros &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º34'11,60''S  74º36'34,51''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Campo Serio &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 1º47'39,70''S  74º42'21,80''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Rumi Tuni &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º3'13,40''S  74º26'10,90''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; San Rafael &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º21'52,39''S  74º6'39,51''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Copal Urco &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º20'56,50''S  73º47'23,30''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Santa Clotilde &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(CS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º29'22,16''S  73º40'39,37''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tacsha Curaray &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 2º48'48,45''S  73º32'27,26''O&lt;br /&gt;&lt;br /&gt;En nuestro esquema sabemos que vamos a tener 2 tipos distintos de estaciones: cliente y repetidor, así que lo primero que vamos a hacer es crear dos sistemas, uno para clientes y otro para repetidores.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SEQC-3Dk1pI/AAAAAAAAAYU/fi9Diswa1jo/s1600-h/propiedades_redes.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SEQC-3Dk1pI/AAAAAAAAAYU/fi9Diswa1jo/s320/propiedades_redes.png" alt="" id="BLOGGER_PHOTO_ID_5207290348101228178" border="0" /&gt;&lt;/a&gt;Pinchamos en "Archivo -&gt; Propiedades de redes" o directamente sobre el iconito que veis a la izquierda. Os saldrá un diálogo en el que podréis el nombre de vuestra red y demás asuntos, os pego cómo lo he dejado yo...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div  style="border-style: dotted; padding: 0.5em; text-align: right; float: right; max-width: 50%;font-size:0.7em;"&gt;&lt;span style="font-weight: bold; padding-left: 0.3em;color:grey;" &gt;Canales de 802.11:&lt;/span&gt;&lt;br /&gt;Canal 01: 2.412 Ghz.&lt;br /&gt;Canal 02: 2.417 Ghz.&lt;br /&gt;Canal 03: 2.422 Ghz.&lt;br /&gt;Canal 04: 2.427 Ghz.&lt;br /&gt;Canal 05: 2.432 Ghz.&lt;br /&gt;Canal 06: 2.437 Ghz.&lt;br /&gt;Canal 07: 2.442 Ghz.&lt;br /&gt;Canal 08: 2.447 Ghz.&lt;br /&gt;Canal 09: 2.452 Ghz.&lt;br /&gt;Canal 10: 2.457 Ghz.&lt;br /&gt;Canal 11: 2.462 Ghz.&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Odz8IS0Tz3k/ST1HIoZXFMI/AAAAAAAAAlM/69SdTBm63B8/s1600-h/Propiedades_redes.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 200px; height: 147px;" src="http://1.bp.blogspot.com/_Odz8IS0Tz3k/ST1HIoZXFMI/AAAAAAAAAlM/69SdTBm63B8/s200/Propiedades_redes.png" alt="" id="BLOGGER_PHOTO_ID_5277452551956403394" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ahora la explicación de por qué lo he puesto así:&lt;/span&gt;&lt;br /&gt;Necesitamos crear 2 tipos de redes, una para la red troncal, que podamos visualizar completa para ver una perspectiva de la red completa, y otra para las redes difusión, para ver cada estación si enlaza con su repetidor. En estas últimas, como luego querremos poder verlas aisladas una a una, y entre ellas no están enlazadas, creamos una subred para cada estación, mientras que en la troncal, también querremos poder ajustar cada enlace, por lo que introducimos también una red por cada enlace de red troncal.&lt;br /&gt;Todas las redes tienen la misma configuración. Son redes de difusión, a las que le he agregado una pérdida adicional de un 20% por bosque (selva) y estamos en un clima continental sub-tropical.&lt;br /&gt;¿Y por qué he puesto las frecuencias entre 2400 y 2474MHz? pues bien, en &lt;a href="http://es.wikipedia.org/wiki/802.11"&gt;802.11&lt;/a&gt;, tenemos los canales útiles que os pongo arriba. Las frecuencias que aparecen son las frecuencias centrales de cada canal, pero luego cada canal tiene un ancho de banda aproximado de 22.5MHz, por lo que usa 11.25MHz por abajo y 11.25MHz por arriba, así que redondeando a la alza diremos que usa 12MHz por arriba y 12MHz por abajo. Si restamos a la frecuencia central del primer canal 12MHz nos quedan 2400MHz (o 2.4GHz) y si sumamos 12MHz a la frecuencia central del último canal nos quedan 2474MHz (o 2.474GHz). El lector avisado se habrá percatado ya de que si el ancho de banda de un canal es de 22.5MHz y los canales tienen una separación de sólo 5MHz entre sí, los canales se solapan. ¡Efectivamente! Por eso decimos que en &lt;a href="http://es.wikipedia.org/wiki/802.11"&gt;802.11&lt;/a&gt; (el estándar de WiFi) tenemos 3 canales no interferentes (el 1, 6 y 11). En realidad, serán canales no interferentes dos canales cualquiera que estén separados 5 canales (25MHz) entre sí, pero si escogemos los canales 1,6 y 11 tendremos 3 canales sin interferencias mientras que cualquier otra combinación sólo nos da 2 canales no interferentes. Ésto de escoger canales no interferentes es bastante importante, pues si dos estaciones están transmitiendo en frecuencias solapadas provocarán colisiones e interferencias entre sí que bajarán nuestra tasa de transferencia, y está claro que cuanto mayor tasa de transferencia tengamos, mejor servicio podremos prestar.&lt;br /&gt;&lt;br /&gt;La selección del modelo estadístico accidental viene debida a que en este modelo no se nos solicita % de ubicaciones, y dado que nuestra red será fija, no queremos asegurar servicio en un cierto % de ubicaciones, sino un % de tiempo concreto. Los valores que ahí hay que poner en cada caso para optimizar aún están en estudio, así que los he fijado a los que Radio Mobile trae por defecto.&lt;br /&gt;&lt;br /&gt;Lo siguiente que vamos a hacer es crear los distintos sistemas que formarán nuestra red. Os voy a ahorrar la búsqueda en los dispositivos del mercado contándoos lo que hay instalado en esta red. Diferenciamos 3 tipos de sistemas:&lt;br /&gt;- Sistema cliente: los clientes enlazan con la torre a través de un router Linksys transmitiendo a 17dBm que dispone de una antena yagi de 9dBi de ganancia.&lt;br /&gt;- Sistema repetidor (enlace de distribución): es la sección del repetidor que se encarga del enlace con el cliente. Dispone de una tarjeta CM9 transmitiendo a 17dBm y una antena yagi de 9dBi de ganancia.&lt;br /&gt;- Sistema repetidor (enlace troncal): es la sección del repetidor que se encarga del enlace con los repetidores adyacentes. Dispone de una tarjeta inalámbrica Ubiquiti SR2, transmitiendo a 26dBm y una antena de grilla Hyperlink de 24dBi de ganancia.&lt;br /&gt;&lt;br /&gt;Estos datos son muy importantes puesto que en función del tipo de emisor que tengamos sabremos cuánta potencia estamos suministrando a su antena, y en función de la antena sabremos cuánta ganancia estamos añadiendo al enlace. Para tener todos estos datos, nos vamos a las hojas de características de las tarjetas inalámbricas, antenas y cables coaxiales que usaremos y veremos la potencia que suministramos a nuestro sistema, las pérdidas en los cables y la ganancia de las antenas para nuestra frecuencia de trabajo de (2.4GHz). Aquí podéis ver las hojas de características:&lt;br /&gt;&lt;a href="http://isf.uc3m.es/descargas_publicas/Ficheros/hojas_tecnicas/tarjetas_inalambricas/CM9.pdf"&gt;Tarjeta CM9&lt;/a&gt;&lt;br /&gt;&lt;a href="http://isf.uc3m.es/descargas_publicas/Ficheros/hojas_tecnicas/tarjetas_inalambricas/sr2datasheet.pdf"&gt;Tarjeta SR2&lt;/a&gt;&lt;br /&gt;&lt;a href="http://isf.uc3m.es/descargas_publicas/Ficheros/hojas_tecnicas/antenas/hg2424g.pdf"&gt;Antenas grilla&lt;/a&gt;&lt;br /&gt;&lt;a href="http://isf.uc3m.es/descargas_publicas/Ficheros/hojas_tecnicas/cable_coaxial/lmr400_a.pdf"&gt;Cable coaxial de bajas pérdidas LRM-400&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;En sudamérica, las normas que rigen sobre la potencia radiada equivalente y demás asuntos técnicos son las mismas que en EEUU. Ésto tiene una ventaja en nuestro caso, y es que en Europa, la PIRE (Potencia Radiada Equivalente) máxima es de 100mW mientras que en EEUU es de 1W. Tener un tope máximo de 1W nos permitirá alcanzar distancias mayores. También tenemos que tener en cuenta los canales en los que es capaz de trabajar nuestra tarjeta inalámbrica para el espectro WiFi de América. Por ejemplo, en la hoja de características de la CM9 vemos que trabaja desde los canales 1 al 11, lo que explica el por qué de que arriba sólo os haya puesto los primeros 11 canales de WiFi. Asimismo, también tendremos en cuenta que si queremos alcanzar distancias muy largas, deberemos escoger una modulación para nuestra señal que sea más robusta frente a errores. Si trabajamos a 6Mbps la modulación será tal que se podrán enviar menos bits por símbolo (la velocidad será inferior), pero habrá menor probabilidad de error, lo cual es bueno en un medio con tantos errores como es un clima tropical con mucha humedad, y además, cuando se trabaja en estas modulaciones las tarjetas inalámbricas tienen mayor sensibilidad (son capaces de demodular señales que llegan con menor potencia) y además transmiten con mayor potencia. Todo esto hará que si queremos llegar a distancias muy largas, lo mejor será establecer una tasa de transferencia de &lt;span style="font-weight: bold;"&gt;6 Mbps. Para esta tasa, vemos que la tarjeta SR2 tiene una sensibilidad de -94dBm y una potencia de transmisión de 26dBm. &lt;/span&gt;Utilizar la más robusta de las modulaciones tendrá sentido para nuestros enlaces largos, pero para nuestros enlaces cortos (los que sirven la señal desde una torre a un puesto de salud) podremos perfectamente utilizar una tasa de transferencia de 54Mbps (máximo de 802.11g). Así pues, &lt;span style="font-weight: bold;"&gt;para 54Mbps la tarjeta CM9 (es la que usamos en los enlaces de distribución) tendrá una sensibilidad de -74dBm y una potencia de transmisión&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Bien, conocido ésto, nos pasamos a la pestaña de "Topología". En esta pestaña, símplemente tendremos que asegurarnos de que todas nuestras subredes creadas están visibles y tienen seleccionada topología "Red de datos. Topología estrella (Master/Esclavo)", tal como muestro a continuación...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0PFgsCtYI/AAAAAAAAAkM/dKaF_0w8JgI/s1600-h/Topologia.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 238px;" src="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0PFgsCtYI/AAAAAAAAAkM/dKaF_0w8JgI/s320/Topologia.png" alt="" id="BLOGGER_PHOTO_ID_5277390925696513410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Con todos estos datos ya podemos rellenar nuestra pestaña de "Sistemas". En nuestro sistema estamos usando 3 tipos de sistemas:&lt;br /&gt;&lt;br /&gt;Sistema cliente...&lt;br /&gt;formado por un linksys con antena yagi y unos metros de cable coaxial dependientes de la distribución del puesto o centro de salud.&lt;br /&gt;&lt;br /&gt;Sistema repetidor (enlace distribución)...&lt;br /&gt;formado por una tarjeta CM9 con antena yagi y un metro de cable coaxial.&lt;br /&gt;&lt;br /&gt;Sistema repetidor (enlace troncal)...&lt;br /&gt;formado por una tarjeta SR2 con antena de grilla hyperlink.&lt;br /&gt;&lt;br /&gt;Pero para simplificar este ejemplo, vamos a suponer que el sistema del cliente y el del repetidor para el enlace de distribución fueran el mismo, es decir, que abajo en el puesto de salud no tuviéramos un linksys, sino otra tarjeta CM9 recibiendo. En cualquier caso, quede dicho que para un diseño más exaustivo habría que diferenciar estos dos sistemas. Pongo pantallazos de cómo he rellenado esta pestaña en función de los valores que obtenemos de las hojas de características que os puse arriba.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Odz8IS0Tz3k/ST0cKVEqTTI/AAAAAAAAAkU/ujNZjlBK9zU/s1600-h/Enlace_Troncal.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 236px;" src="http://3.bp.blogspot.com/_Odz8IS0Tz3k/ST0cKVEqTTI/AAAAAAAAAkU/ujNZjlBK9zU/s320/Enlace_Troncal.png" alt="" id="BLOGGER_PHOTO_ID_5277405302129052978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Sistema Troncal...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_Odz8IS0Tz3k/ST0ccBtaQ4I/AAAAAAAAAkc/H6vbVlNEMQQ/s1600-h/Enlace_Distribucion.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 234px;" src="http://2.bp.blogspot.com/_Odz8IS0Tz3k/ST0ccBtaQ4I/AAAAAAAAAkc/H6vbVlNEMQQ/s320/Enlace_Distribucion.png" alt="" id="BLOGGER_PHOTO_ID_5277405606168904578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Sistema de Distribución...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El siguiente paso es la pestaña "Miembros". Ahora agregaremos cada unidad a la red a la que pertenece. Ésta parte es divertida, consiste en ir diciendo, para la red de distribución de tacsha, los miembros serán tachsa y el PS de tacsha, y así para todos los enlaces de distribución. Luego en los enlaces troncales ir añadiendo para tacsha-santa los miembros tacha curaray y santa clotilde, e indicando correctamente que el sistema que utilizarán será en este caso el sistema troncal, mientras en el anterior era el sistema distribución.&lt;br /&gt;Tendremos que ir unidad a unidad ajustando también la altura de la antena, diciendo que no tome el valor del "Sistema", sino seleccionando "Otro" y estableciendo su valor a mano. Para que probéis, os pongo las alturas de las antenas de cada nodo:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cabo Pantoja (Torre):&lt;/span&gt; 42m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Torres Causana &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 45m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tempestad &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 60m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tupac Amaru &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 39m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Angoteros &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 66m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Campo Serio &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 66m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Rumi Tuni &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 90m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; San Rafael &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 90m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Copal Urco &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 54m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Santa Clotilde &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 72m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tacsha Curaray &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(Torre)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 72m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cabo Pantoja &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(CS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Torres Causana &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tempestad &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tupac Amaru &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 3m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Angoteros &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Campo Serio &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Rumi Tuni &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; San Rafael &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 3m&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Copal Urco &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Santa Clotilde &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(CS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span&gt;3m&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tacsha Curaray &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(PS)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; 3m&lt;br /&gt;&lt;br /&gt;En cuanto al apuntamiento de las antenas, que ajustamos en "Azimut de Antena", tendremos que ir unidad a unidad diciendo que apunte correctamente a la unidad destino del enlace. Es un poco pesado, pero hay que hacerlo, ya que como tenemos antenas directivas, si no apuntamos bien, nuestro balance de enlace será una birria :). Os pego ejemplos de un enlace troncal y de uno de distribución.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ejemplo del enlace de distribución de la torre de Tacsha Curaray con su Puesto de Salud:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0oLyLduxI/AAAAAAAAAkk/oIF_fb3Rfkc/s1600-h/Miembros_difusion_torre.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 236px;" src="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0oLyLduxI/AAAAAAAAAkk/oIF_fb3Rfkc/s320/Miembros_difusion_torre.png" alt="" id="BLOGGER_PHOTO_ID_5277418521261619986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Torre...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Odz8IS0Tz3k/ST0ocLqF_CI/AAAAAAAAAks/_hee3S0lxfA/s1600-h/Miembros_Difusion_cliente.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 236px;" src="http://1.bp.blogspot.com/_Odz8IS0Tz3k/ST0ocLqF_CI/AAAAAAAAAks/_hee3S0lxfA/s320/Miembros_Difusion_cliente.png" alt="" id="BLOGGER_PHOTO_ID_5277418802978880546" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Puesto de Salud...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ejemplo de enlace troncal entre la torre de Santa Clotilde con la de Copal Urco:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_Odz8IS0Tz3k/ST0pTIDK2VI/AAAAAAAAAk0/8pTqBh_o0YY/s1600-h/Miembros_Troncal_1.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 238px;" src="http://2.bp.blogspot.com/_Odz8IS0Tz3k/ST0pTIDK2VI/AAAAAAAAAk0/8pTqBh_o0YY/s320/Miembros_Troncal_1.png" alt="" id="BLOGGER_PHOTO_ID_5277419746903120210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Torre de Santa Clotilde...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Odz8IS0Tz3k/ST0pirxpamI/AAAAAAAAAk8/t2h-wMDiZWQ/s1600-h/Miembros_Troncal_2.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 236px;" src="http://3.bp.blogspot.com/_Odz8IS0Tz3k/ST0pirxpamI/AAAAAAAAAk8/t2h-wMDiZWQ/s320/Miembros_Troncal_2.png" alt="" id="BLOGGER_PHOTO_ID_5277420014191340130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Torre de Copal Urco...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Y así a lo tonto, hemos casi llegado al final del diseño de nuestra red, sólo nos queda la pestaña "Estilo", que viene a ser la que nos dice con qué colorines nos pinta las líneas dependiendo de los dBs por encima de la sensibilidad de la tarjeta receptora en cada enlace. Normalmente, y debido a las variaciones que sufre un canal inalámbrico y más en entornos tan húmedos y lluviosos como la selva, diremos a Radio Mobile que nos pinte la línea verde sólo cuando nuestro "Rx Relativo" supere los 20dB, y que se ponga amarilla entre 3 y 20dB, lo que nos hará saber qué enlaces no se pueden conseguir con el diseño actual (línea roja), cuáles se podrían conseguir con ciertos retoques quizás (línea amarilla) y cuáles están bien dimensionados (línea verde). Os pongo un pantallazo de esta configuración...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0rFye1x8I/AAAAAAAAAlE/xG5GQInt7_I/s1600-h/Estilo.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 238px;" src="http://4.bp.blogspot.com/_Odz8IS0Tz3k/ST0rFye1x8I/AAAAAAAAAlE/xG5GQInt7_I/s320/Estilo.png" alt="" id="BLOGGER_PHOTO_ID_5277421716798556098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Finalmente, ya tenemos toda nuestra red configurada, así que pulsamos en "OK" y vemos el resultado. La impresión inicial será...pufffff, ¿aquí no enlaza nada con nada o qué? Jeje, bueno, tranquilos, ésto se debe a que nuestras coordenadas GPS no eran del todo exactas, y habrá que afinarlas, pero no os preocupéis que eso lo haremos en la siguiente entrada. Ya habéis tenido bastante por hoy para llevar tanto tiempo sin currar en Radio Mobile :).&lt;br /&gt;&lt;br /&gt;Y nada, a comer muchas verduras. Nos vemos en la siguiente entrada de "Diseño de redes inalámbricas con Radio Mobile".&lt;br /&gt;&lt;br /&gt;¡A cuidarse!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-4082820931131235367?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/4082820931131235367/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=4082820931131235367' title='13 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/4082820931131235367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/4082820931131235367'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/12/diseo-de-redes-inalmbricas-con-radio.html' title='Diseño de redes inalámbricas con Radio Mobile (III)'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_Odz8IS0Tz3k/SEHFAnDk1lI/AAAAAAAAAX0/cto_7oGiK84/s72-c/creando_mapa1.png' height='72' width='72'/><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-1542816307700972749</id><published>2008-12-02T17:02:00.022Z</published><updated>2008-12-03T10:25:04.451Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='skype'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='mono'/><title type='text'>Integración con SkypeWeb API desde ASP.net y Mono</title><content type='html'>&lt;blockquote&gt;Todos los códigos de este artículo os los podéis descargar desde:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Proyecto de Visual Web Developer Express 2005, &lt;a href="http://www.nidea-soluciones.com/Descargas/PruebaSkype.rar"&gt;aquí&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Solución de Monodevelop, &lt;a href="http://www.nidea-soluciones.com/Descargas/skypeApi.rar"&gt;aquí&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br /&gt;En este artículo vamos a ver una pequeña integración con el &lt;a href="https://developer.skype.com/Docs/Web"&gt;API de Skype para plataformas web&lt;/a&gt;. Lo que vamos a hacer es implementar un &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;pequeño control de presencia&lt;/span&gt; que podremos utilizar en nuestra web. La idea es que, a través del API Web de Skype, interrogar sobre nuestro estado en Skype y, en base a la respuesta, mostrar un icono de estado.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(153, 153, 0);"&gt;¿Para qué nos puede servir esto, os preguntareis?&lt;/span&gt; Pues, por ejemplo, Skype es una muy buena opción para dar soporte a usuario y siempre queda bien poner un icono de que estamos online o no en nuestra página web. También sirve como base para cuando Skype ofrezca más servicios vía web, en fin, y como curiosidad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;Vamos al lío entonces...&lt;/span&gt;&lt;br /&gt;Lo primero que tenemos que hacer es configurar Skype para permitirle que notifique nuestro estado. En &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Herramientas -&gt; Opciones&lt;/span&gt;, en la pestaña Privacidad, marcaremos la opción "Mostrar mi estado de conexión en la web":&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/STV9rYNNwaI/AAAAAAAAAYE/mkuIZVp31hQ/s1600-h/skype1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 321px;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/STV9rYNNwaI/AAAAAAAAAYE/mkuIZVp31hQ/s400/skype1.jpg" alt="" id="BLOGGER_PHOTO_ID_5275260722720129442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Una vez marcada esta opción, el servidor de Skype permitirá que le interroguen sobre el estado de nuestro usuario a través de su API. Skype provee de dos métodos por los que obtener el estado de un usuario: vía consulta DNS, vía petición HTTP. Nosotros vamos a ver la segunda opción. La sintaxis para interrogar es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic; color: rgb(102, 102, 0);"&gt;http://mystatus.skype.com/[nombre_usuario].extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En [nombre_usuario] pondremos el usuario sobre el que queremos obtener el estado, en este caso, será el nuestro, y en extensión le indicaremos a Skype cómo queremos que nos devuelva la información. Disponemos de cuatro opciones:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Sin extensión&lt;/span&gt;: Skype devuelve una imagen con el estado del usuario (en la documentación se muestra las diferentes imágenes de que dispone)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;xml:&lt;/span&gt; devuelve un XML con el estado del usuario en diferentes idiomas&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;txt: &lt;/span&gt;devuelve el estado del usuario en formato texto en el idioma del explorador&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;num:&lt;/span&gt; devuelve un código equivalente al estado del usuario (ésta es la opción que vamos a utilizar).&lt;/li&gt;&lt;/ul&gt;Lo que vamos a hacer, por lo tanto, es lanzar &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;una petición http al servidor de Skype&lt;/span&gt;, obtener la respuesta y en base al código que nos devuelva, poner una imagen u otra en pantalla. Los posibles códigos de retorno son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;0: desconocido&lt;/li&gt;&lt;li&gt;1: offline&lt;/li&gt;&lt;li&gt;2: online&lt;/li&gt;&lt;li&gt;3: fuera&lt;/li&gt;&lt;li&gt;4: no disponible&lt;/li&gt;&lt;li&gt;5: no molestar&lt;/li&gt;&lt;li&gt;6: invisible&lt;/li&gt;&lt;li&gt;7: skype me&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;Vamos a codificar el asunto&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;La página de demo la podéis encontrar pinchando &lt;a href="http://demos.formacionsantaana.com/skypeApi/Default.aspx"&gt;aquí&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;El proyecto está realizado tanto para Monodevelop (para los de Linux) como para Web Developer Express Edition 2005 (para los de Windows). La única diferencia es que Mono &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;no dispone de soporte para el AJAX de ASP.net&lt;/span&gt; y en la versión de Mono está quitado el tema de AJAX.&lt;br /&gt;&lt;br /&gt;La pantalla del proyecto es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/STZYmtZsSGI/AAAAAAAAAYM/sSeH6X2Hk-Y/s1600-h/skype2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 257px;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/STZYmtZsSGI/AAAAAAAAAYM/sSeH6X2Hk-Y/s400/skype2.jpg" alt="" id="BLOGGER_PHOTO_ID_5275501435556743266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Introduciremos el nombre del usuario a interrogar y pulsaremos sobre el botón &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;"Buscar desde Servidor"&lt;/span&gt;. El código que se ejecuta en este botón es:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/STZa9DVPM5I/AAAAAAAAAYU/E9f_7sxxfEQ/s1600-h/skype3.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 254px;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/STZa9DVPM5I/AAAAAAAAAYU/E9f_7sxxfEQ/s400/skype3.jpg" alt="" id="BLOGGER_PHOTO_ID_5275504018424017810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo primero que se hace es realizar un &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;HttpWebRequest &lt;/span&gt;hacia el servidor de Skype pasándole el usuario que se ha introducido en el textbox. Obtenemos la respuesta y creamos un Stream para ir leyendo el resultado que nos devuelve Skype.&lt;br /&gt;&lt;br /&gt;Al leer el código de la respuesta, ponemos en pantalla una imagen correspondiente al estado del usuario. En la carpeta img disponemos de 8 imágenes llamadas 0.png, 1.png, 2.png,... en función del código devuelto, pondremos una u otra.&lt;br /&gt;&lt;br /&gt;El resultado es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/STZcTmWl9OI/AAAAAAAAAYc/-PIEC7Lu5R4/s1600-h/skype4.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 257px;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/STZcTmWl9OI/AAAAAAAAAYc/-PIEC7Lu5R4/s400/skype4.jpg" alt="" id="BLOGGER_PHOTO_ID_5275505505293694178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En el proyecto de Web Developer, le he puesto un UpdatePanel para que no haya refrescos de pantalla, mientras que en Mono no está puesto.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;Control de Presencia&lt;/span&gt;&lt;br /&gt;Con esta pequeña integración podemos poner un icono en nuestra página web indicando nuestro estado en Skype. Tenemos dos alternativas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Poner un timer para que vaya refrescando el estado cada x tiempo.&lt;/li&gt;&lt;li&gt;Realizar esta operación en el Page_Load y actualizar el estado solamente cuando se acceda a la página.&lt;/li&gt;&lt;/ul&gt;También existe la posibilidad de implementar las llamadas desde Javascript a través de un Proxy y manejar la respuesta directamente desde la página (en Javascript).&lt;br /&gt;&lt;br /&gt;En fin, espero que os haya gustado este pequeño post, y que os sirva para investigar más allá y para poner vuestro icono de presencia en vuestras webs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-1542816307700972749?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/1542816307700972749/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=1542816307700972749' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1542816307700972749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1542816307700972749'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/12/integracin-con-skypeweb-api-desde.html' title='Integración con SkypeWeb API desde ASP.net y Mono'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_uUP4eiIAPJ8/STV9rYNNwaI/AAAAAAAAAYE/mkuIZVp31hQ/s72-c/skype1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-2721036647463512066</id><published>2008-11-03T16:21:00.003Z</published><updated>2008-11-13T08:59:07.881Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='open flash chart'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Gráficos dinámicos con Open Flash Chart en ASP.NET y UpdatePanels</title><content type='html'>&lt;blockquote&gt;Todos los códigos de este post os los podéis descargar desde &lt;a href="http://www.nidea-soluciones.com/descargas/DemoOFC.rar"&gt;aquí&lt;/a&gt;. Todo el proyecto ha sido realizado con Visual Web Developer 2005 Express Edition.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Buenas, hace tiempo que tenía ganas de escribir este artículo sobre la creación de gráficos sobre ASP.NET utilizando la librería flash &lt;a href="http://teethgrinder.co.uk/open-flash-chart/download.php"&gt;OpenFlashChart&lt;/a&gt;. Este componente flash nos permite crear gráficos muy versátiles, de muy diversos tipos y totalmente customizables en estilo. Además, es código abierto y libre tanto para uso personal como comercial. Aunque ya ha sido liberada la versión 2 (con cambios sustanciales en la forma de pasar los datos), este artículo está basado en la versión 1.9.7 que fue la que inicialmente me descargué en su momento y con la que trabajé.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Introducción del por qué y el cómo&lt;/span&gt;&lt;br /&gt;En la página de &lt;a href="http://teethgrinder.co.uk/open-flash-chart/"&gt;OFC&lt;/a&gt; podéis encontrar multitud de ejemplos, tutoriales, foros, etc. por lo que no voy a explicar aquí los diferentes tipos de gráficos y las funcionalidades de las que dispone OFC.&lt;br /&gt;&lt;br /&gt;Después de leer la documentación y de probar con la librería, me surgió un problema, la necesidad de &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;pasarle datos dinámicamente desde código&lt;/span&gt; al gráfico y que se refrescará utilizando UpdatePanels de ASP.net. Es decir, poder generar, actualizar, cambiar el tipo de gráfico, todo ello desde código (entiéndase base de datos) y utilizando el AJAX de ASP.NET. Para conseguir tal propósito, me he apoyado en la librería .NET que viene con la descarga de OFC llamada "OpenFlashChartLibrary.dll". Esta librería trae un control de servidor para renderizar el gráfico, pero en este proyecto no se utiliza, sólo utilizaremos las clases que nos permiten generar el código de los gráficos que entiende el componente flash.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;¿Qué es lo que queremos conseguir?&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;Puedes acceder a las páginas de demo pulsando &lt;a href="http://demos.formacionsantaana.com/demoOfc/Grafico1.aspx"&gt;aquí&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;Si véis en las páginas de demo, lo que queremos conseguir es un entorno basado en AJAX (UpdatePanels) para la generación y actualización de gráficos. En el ejemplo hay dos páginas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;La primera (Ejemplo de gráfico dinámico)&lt;/span&gt;: permite generar un gráfico dinámicamente y anexarle dos series más. Además podemos elegir si cada serie la queremos en forma de barras o líneas. Si elegimos el gráfico como tarta sólo se renderiza la primera serie. Además el gráfico recalcula automáticamente los márgenes de valores máximos a mostrar en base a los datos introducidos (hay un error en la demo, sólo recalcula para la primera serie, lo siente).&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SRvr_Xxc-PI/AAAAAAAAAX0/VOnaeDBaA3k/s1600-h/ofc1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 270px;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SRvr_Xxc-PI/AAAAAAAAAX0/VOnaeDBaA3k/s400/ofc1.jpg" alt="" id="BLOGGER_PHOTO_ID_5268063663085648114" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SQ8vwtXl4NI/AAAAAAAAAXM/mchPjz5sLMM/s1600-h/ofc1.jpg"&gt;&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;La segunda (Ejemplo de varios gráficos):&lt;/span&gt; nos permite generar dos gráficos simultáneamente y actualizarlos de forma independiente, cada uno con sus controles de tipo de gráfico y la serie a mostrar.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SRvsJN7ycXI/AAAAAAAAAX8/aMI1Kfql4yo/s1600-h/ofc2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 270px;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SRvsJN7ycXI/AAAAAAAAAX8/aMI1Kfql4yo/s400/ofc2.jpg" alt="" id="BLOGGER_PHOTO_ID_5268063832243335538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;¿Cómo lo hacemos?&lt;/span&gt;&lt;br /&gt;Todo el tema se basa en la clase &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;RenderizadorGrafico.cs&lt;/span&gt; que se encuentra en la carpeta App_Code del proyecto. Dicha clase se apoya en la libreria OpenFlasChartLibrary para la generación del código del gráfico. El funcionamiento general es el siguiente:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Le pasamos a la clase la primera serie a pintar junto con varios valores generales (título del gráfico, posiciones decimales, etc)&lt;/li&gt;&lt;li&gt;Si tenemos más series le vamos pasando cada una de las series restantes (&lt;span style="font-weight: bold; color: rgb(153, 153, 0);"&gt;debe coincidir el número de valores de la serie con los del eje X&lt;/span&gt;), con su nombre.&lt;/li&gt;&lt;li&gt;Llamamos al método &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;RenderizarGrafico&lt;/span&gt; pasándole el código del gráfico (devuelto por los métodos anteriores), la ubicación del componente flash OFC, el div donde queremos que se coloque el gráfico y la página en la que estamos. Este método se encargará de generar el código javascript necesario para mostrar el gráfico y lo inyectará en la página.&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;La clase RenderizadorGrafico.cs en detalle&lt;/span&gt;&lt;br /&gt;La clase RenderizadorGrafico.cs es la encargada de generar el código que entiende el componente OFC para la generación de los gráficos. Esta clase se apoya en la librería OpenFlashChartLibrary.dll que viene con OFC y que simplifica la generación del código. Los métodos de los que dispone la clase son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;RenderizarGrafico&lt;/span&gt;: se le pasa el código del gráfico (obtenido con los otros métodos), la ruta del componente OFC, el div donde colocar el gráfico (uno por cada gráfico) y la página que llama al método. Este método tiene una sobrecarga para cuando tenemos varios gráficos en pantalla en la que le pasamos arrays con los diferentes códigos y los divs donde colocar cada gráfico.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;GenerarCodigoGrafico&lt;/span&gt;: este método se encarga de generar el código del gráfico que le pasaremos al método RenderizarGrafico. A este método le pasaremos la serie tanto para el eje X como para el eje Y y diferentes parámetros de visualización. Este método dispone de una sobrecarga para la representación de gráficos en forma de tarta que se manejan de forma diferente. En esta sobrecarga se le pasan los valores en formato Object[,], pasando en la primera dimensión el valor y en la segunda la etiqueta.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;AnexarGrafico:&lt;/span&gt; este método permite anexarle más series a un gráfico.&lt;/li&gt;&lt;/ul&gt;La clase define al inicio el estilo que se va a aplicar para los gráficos, teniendo varios struct y constantes que se van utilizando a lo largo de los métodos. En cualquier momento se puede modificar dichos valores para cambiar el aspecto de nuestros gráficos.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ854OWQxtI/AAAAAAAAAXc/zk6w6k21lPU/s1600-h/ofc3.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 189px;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ854OWQxtI/AAAAAAAAAXc/zk6w6k21lPU/s400/ofc3.jpg" alt="" id="BLOGGER_PHOTO_ID_5264490127506327250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La clase dispone, al final de un par de métodos que se utilizan para corregir ciertos fallos que me encontré en la librería .net en la generación de gráficos del tipo tarta.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;¿Cómo genera la clase el gráfico?&lt;/span&gt;&lt;br /&gt;La clase, en el método RenderizarGráfico, genera el código javascript necesario para renderizar el gráfico en pantalla. Utiliza el fichero swfobject.js para la incrustación de elementos flash en páginas web y lo inyecta en la página. Para inyectar el código hace uso del elemento &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;ScriptManager&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt; &lt;/span&gt;del AJAX de ASP.net.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ87Y7LFL5I/AAAAAAAAAXk/Kzhp3NgWwjE/s1600-h/ofc4.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 198px;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ87Y7LFL5I/AAAAAAAAAXk/Kzhp3NgWwjE/s400/ofc4.jpg" alt="" id="BLOGGER_PHOTO_ID_5264491788806467474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;¿Cómo le pasamos los datos?&lt;/span&gt;&lt;br /&gt;Tenemos dos formas de pasarle los datos a la clase dependiendo del tipo de gráfico que vamos a realizar. Si vamos a crear un gráfico que &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;no sea del tipo tarta&lt;/span&gt; tendremos que crearnos lo siguiente:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Array de strings con los valores del eje X&lt;/li&gt;&lt;li&gt;Array de doubles con los valores del eje Y&lt;/li&gt;&lt;li&gt;Float con el valor máximo de la gráfica&lt;/li&gt;&lt;li&gt;Float con el valor mínimo&lt;/li&gt;&lt;/ul&gt;Si vamos a generar un gráfico del &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;tipo tarta&lt;/span&gt; tendremos que crearnos lo siguiente:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Array de objects de dos dimensiones (object[2,numero elementos]) que tenga en la dimensión 0 el valor y en la dimensión 1 la etiqueta para ese valor. El componente se encargará de pintarlos en el orden correcto.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Lo último, ¿qué código ponemos en el aspx?&lt;/span&gt;&lt;br /&gt;Finalmente, para que nuestro gráfico se vea correctamente tendremos que crearnos en la página un div donde vaya a ser colocado. Para utilizar AJAX en los refrescos del gráfico, pondremos dicho div dentro de una estructura UpdatePanel y le pondremos los triggers pertinentes.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ9ADwytPmI/AAAAAAAAAXs/KCaxb1LzGAM/s1600-h/ofc5.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 273px;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SQ9ADwytPmI/AAAAAAAAAXs/KCaxb1LzGAM/s400/ofc5.jpg" alt="" id="BLOGGER_PHOTO_ID_5264496922800766562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Final&lt;/span&gt;&lt;br /&gt;Espero que os haya gustado este artículo y que os pueda servir. Personalmente, esta solución se encuentra en entornos de producción y funciona perfectamente. Como siempre, agradeceré cualquier comentario.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-2721036647463512066?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/2721036647463512066/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=2721036647463512066' title='14 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2721036647463512066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2721036647463512066'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/11/grficos-dinmicos-con-openflashchart-en.html' title='Gráficos dinámicos con Open Flash Chart en ASP.NET y UpdatePanels'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_uUP4eiIAPJ8/SRvr_Xxc-PI/AAAAAAAAAX0/VOnaeDBaA3k/s72-c/ofc1.jpg' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-2662159264540048792</id><published>2008-10-06T08:21:00.003Z</published><updated>2008-10-06T08:25:53.892Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='blog'/><category scheme='http://www.blogger.com/atom/ns#' term='concurso'/><title type='text'>Inscripción al concurso de blogs del 20 minutos</title><content type='html'>&lt;div style="text-align: justify;"&gt;He inscrito este blog en el concurso de la revista 20 minutos, en la categoría de mejor blog de tecnología. Si os gusta el contenido que publicamos aquí, os agradeceríamos que nos votaseis en cuanto empiecen las votaciones (15 de Octubre).&lt;br /&gt;&lt;br /&gt;La dirección del concurso es &lt;a href="http://www.20minutos.es/premios_20_blogs"&gt;http://www.20minutos.es/premios_20_blogs&lt;/a&gt; y el nombre con el que se ha inscrito éste es "N-Idea de muchos temas".&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-2662159264540048792?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/2662159264540048792/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=2662159264540048792' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2662159264540048792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2662159264540048792'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/10/inscripcin-al-concurso-de-blogs-del-20.html' title='Inscripción al concurso de blogs del 20 minutos'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-2491581840658462584</id><published>2008-08-27T08:30:00.026Z</published><updated>2008-10-10T09:18:55.607Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Uso de Transacciones en C# con TableAdapters</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;blockquote&gt;Actualización (10-10-2008): el enlace correcto al artículo de Mike Pagel es &lt;a href="http://www.codeproject.com/KB/dotnet/transactionta.aspx"&gt;http://www.codeproject.com/KB/dotnet/transactionta.aspx&lt;/a&gt;. Gracias Diego.&lt;br /&gt;Actualización: ha habido un error con el enlace el artículo de Mike Pagel, podéis descargaros su clase desde la dirección &lt;a href="http://www.nidea-soluciones.com/PruebasAJAX/TransactionSupport.zip"&gt;http://www.nidea-soluciones.com/PruebasAJAX/TransactionSupport.zip&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;En este nuevo artículo voy a abordar el tema de la &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;gestión de transacciones&lt;/span&gt; cuando trabajamos con &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;TableAdapters&lt;/span&gt; generados por Visual Studio. El trabajo con TableAdapters generados por Visual Studio es muy cómodo, en el sentido que genera toda la lógica de acceso a datos y la representación de los mismos con Datatables, pero en el momento en que queremos utilizar transacciones en nuestros accesos a base de datos, el tema se complica. En determinados entornos, sobre todo a la hora de programar sistemas grandes, el uso de transacciones se vuelve inevitable. En este artículo vamos a ver una forma &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;muy cómoda de usar transacciones&lt;/span&gt; con TableAdapters generados por Visual Studio.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Un poquito de teoría&lt;/span&gt;&lt;br /&gt;Antes de nada, vamos a ver un poco cómo va el tema de las transacciones. ¿Para qué sirven las transacciones? Una transacción lo que nos permite es controlar un grupo de sentencias a base de datos de forma que podamos o bien dar marcha atrás a todas las sentencias o bien confirmar el bloque completo. El control del grupo de sentencias lo lleva la base de datos, de forma que el programador sólo debe indicar si se &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;confirma (Commit Transaction)&lt;/span&gt; o &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;no (Rollback Transaction)&lt;/span&gt; el grupo de sentencias. En el siguiente dibujo os pongo un ejemplo:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SMjXqTGK3_I/AAAAAAAAAQE/ZLidS2WKiGw/s1600-h/Transacciones1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SMjXqTGK3_I/AAAAAAAAAQE/ZLidS2WKiGw/s400/Transacciones1.gif" alt="" id="BLOGGER_PHOTO_ID_5244678887753572338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Como podéis ver, desde el momento en el que iniciamos la transacción, todas las operaciones quedan registradas y si realizamos un rollback deshacemos las hechas y si hacemos un commit, la transacción se termina y los cambios quedan confirmados.&lt;br /&gt;Pero, &lt;span style="font-weight: bold; color: rgb(153, 153, 0);"&gt;¿qué pasa si hacemos un select sobre un campo actualizado en una transacción no confirmada?&lt;/span&gt; Buena pregunta, porque se plantea un problema, si la sentencia no está confirmada, el gestor de base de datos no puede asegurar que ese dato sea correcto. En ese caso entran en juego los niveles de aislamiento de transacciones (Isolation Levels) que, básicamente, lo que deciden es cómo se debe comportar el gestor de base de datos en estas situaciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Bueno, al lío&lt;/span&gt;&lt;br /&gt;Vamos a ir paso a paso, lo primero que vamos a hacer es crearnos una aplicación de Windows Forms en C# (me supongo que sabéis hacerlo). Para todo vamos a utilizar la versión gratuita (Express) de visual studio, en concreto Visual C# 2005 Express Edition.&lt;br /&gt;&lt;br /&gt;1. Crearse un proyecto "Aplicación para Windows"&lt;br /&gt;2. En la pantalla principal nos creamos los siguientes controles&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM9sufw_kNI/AAAAAAAAAQM/sOqNlKlrSyI/s1600-h/Transacciones2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM9sufw_kNI/AAAAAAAAAQM/sOqNlKlrSyI/s400/Transacciones2.gif" alt="" id="BLOGGER_PHOTO_ID_5246531636966691026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. Nos creamos una nueva base de datos en &lt;span style="font-weight: bold; color: rgb(0, 102, 0);"&gt;SQL Server 2005 Express Edition&lt;/span&gt; que se llame "&lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;PruebaTransacciones&lt;/span&gt;" con una tabla llamada "&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Tabla1&lt;/span&gt;" que contenga 2 campos "&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Id&lt;/span&gt;" y "&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Nombre&lt;/span&gt;" y otra llamada "&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Tabla2&lt;/span&gt;" con los mismos campos. La definición es la siguiente:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM9vrBjMQ9I/AAAAAAAAAQU/oSeeBpukVFM/s1600-h/Transacciones3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM9vrBjMQ9I/AAAAAAAAAQU/oSeeBpukVFM/s400/Transacciones3.gif" alt="" id="BLOGGER_PHOTO_ID_5246534875851015122" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Nos creamos en nuestro proyecto dos TableAdapters, uno para cada una de las tablas que hemos creado en base de datos.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM9wHk67CAI/AAAAAAAAAQc/JNHUqPmdPcw/s1600-h/Transacciones4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM9wHk67CAI/AAAAAAAAAQc/JNHUqPmdPcw/s400/Transacciones4.gif" alt="" id="BLOGGER_PHOTO_ID_5246535366382127106" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Por ahora, nuestro proyecto y los TableAdapters nos tienen que quedar de la siguiente manera:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM91wGQpW-I/AAAAAAAAAQk/A6gpEfblAf8/s1600-h/Transacciones5.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM91wGQpW-I/AAAAAAAAAQk/A6gpEfblAf8/s400/Transacciones5.gif" alt="" id="BLOGGER_PHOTO_ID_5246541560084519906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM91wcy0JuI/AAAAAAAAAQs/i72GxXKKr-M/s1600-h/Transacciones6.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SM91wcy0JuI/AAAAAAAAAQs/i72GxXKKr-M/s400/Transacciones6.gif" alt="" id="BLOGGER_PHOTO_ID_5246541566133413602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ahora mismo no disponemos de soporte para transacciones porque los tableadapters generados no lo incluyen. Es en este momento cuando le vamos a introducir esa nueva funcionalidad. Vamos a utilizar una clase creada por &lt;span style="font-weight: bold; color: rgb(153, 153, 0);"&gt;Mike Pagel&lt;/span&gt; y que podéis encontrar en su artículo del CodeProject &lt;a href="http://www.codeproject.com/useritems/typed_dataset_transaction.asp"&gt;http://www.codeproject.com/useritems/typed_dataset_transaction.asp&lt;/a&gt;. Lo que vamos a hacer es &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;sobreescribir la clase base de los tableadapters&lt;/span&gt;&lt;span style="color: rgb(51, 153, 153);"&gt; &lt;/span&gt;con esta que incorpora las funcionalidades de las transacciones. Para ello, incluiremos la clase en nuestro proyecto y en las propiedades de los TableAdapters, pondremos el nombre de la clase en la&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt; propiedad BaseClass&lt;/span&gt;:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SM930rM4YcI/AAAAAAAAAQ0/99j79E_aS6U/s1600-h/Transacciones7.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SM930rM4YcI/AAAAAAAAAQ0/99j79E_aS6U/s400/Transacciones7.gif" alt="" id="BLOGGER_PHOTO_ID_5246543837743571394" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En mi caso le he puesto Transaccion.TransactionSupport porque el namespace de la clase es Transaccion.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Utilizar las transacciones&lt;/span&gt;&lt;br /&gt;Ahora que tenemos soporte para transacciones vamos a utilizarlas en nuestra pantalla. Teníamos creados un botón y dos radiobuttons, vamos a programar el evento Click del botón de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM97PgVOH0I/AAAAAAAAAQ8/QjudzWI_QO4/s1600-h/Transacciones8.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM97PgVOH0I/AAAAAAAAAQ8/QjudzWI_QO4/s400/Transacciones8.gif" alt="" id="BLOGGER_PHOTO_ID_5246547597217111874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo que hacemos es insertar un registro en la tabla1 y confirmamos o deshacemos la operación en base a los radiobuttons que se pusieron. Ahora vamos a modificar un poco el código para realizar una operación &lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;sobre las dos tablas&lt;/span&gt; compartiendo la transacción:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SM98SdRuo5I/AAAAAAAAARE/wdfDCdvIw2c/s1600-h/Transacciones9.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SM98SdRuo5I/AAAAAAAAARE/wdfDCdvIw2c/s400/Transacciones9.gif" alt="" id="BLOGGER_PHOTO_ID_5246548747448394642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En este caso, hemos igualado la transacción secundaria con la principal para poder interactuar con varias tablas a la vez. El último paso es: ¿cómo pasar una transacción por diferentes clases y métodos para actuar sobre múltiples tablas sin tenerlo todo en el mismo método? La pregunta es larga pero la respuesta es corta, veamos la siguiente modificación al método del botón:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM-BzrWu0iI/AAAAAAAAARM/-cRcE-HJ38c/s1600-h/Transacciones10.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SM-BzrWu0iI/AAAAAAAAARM/-cRcE-HJ38c/s400/Transacciones10.gif" alt="" id="BLOGGER_PHOTO_ID_5246554815721296418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En este caso, estamos instanciando la clase &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;ManejadorTabla2&lt;/span&gt; y llamando al método &lt;span style="font-weight: bold; color: rgb(153, 102, 51);"&gt;ActualizarTabla&lt;/span&gt; para guardar los cambios en la tabla2. A este método, aparte de los registros le estamos pasando la transacción. El código interno del método es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SM-CblI4D1I/AAAAAAAAARU/Y8n1km_sHDg/s1600-h/Transacciones11.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SM-CblI4D1I/AAAAAAAAARU/Y8n1km_sHDg/s400/Transacciones11.gif" alt="" id="BLOGGER_PHOTO_ID_5246555501247336274" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo que hacemos en este método es controlar si se pasa como argumento una transacción o no. Si el método falla, lo que hacemos es devolver un false para el método que controla la transacción &lt;span style="font-weight: bold; color: rgb(204, 102, 0);"&gt;decida qué hay que hacer&lt;/span&gt;. En caso que no se pase transacción, el método se comporta de forma normal.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Conclusión&lt;/span&gt;&lt;br /&gt;Ciertamente, el uso de transacciones en entornos grandes es obligatorio. No nos podemos plantear un sistema sin control de transacciones porque antes o después se haría inviable su programación. Creo que esta solución al problema es muy simple, elegante y efectiva y os animo a probarla. Como siguiente paso para el que guste de estos temas queda la modificación de la clase para adaptarlas a entornos no SQLServer como puede ser MySql. El código es muy sencillo y creo que se podría modificar rápidamente.&lt;br /&gt;&lt;br /&gt;En fin espero que os haya gustado este articulillo sobre transacciones.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-2491581840658462584?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/2491581840658462584/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=2491581840658462584' title='12 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2491581840658462584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2491581840658462584'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/08/uso-de-transacciones-en-c-con.html' title='Uso de Transacciones en C# con TableAdapters'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_uUP4eiIAPJ8/SMjXqTGK3_I/AAAAAAAAAQE/ZLidS2WKiGw/s72-c/Transacciones1.gif' height='72' width='72'/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-5665931870877814458</id><published>2008-07-03T10:15:00.016Z</published><updated>2008-08-08T14:56:51.408Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='itextsharp'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Motor de Informes Dinámicos con itextsharp (II)</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:georgia;"&gt;Hola de nuevo a todos, ha pasado un tiempo desde la primera parte del tutorial, pero ya he encontrado tiempo para escribir esta segunda parte (más interesante que la primera). En la primera parte vimos cómo funcionaba la librería itext# para generar informes PDF al vuelo. En esta segunda parte lo que veremos será cómo crear plantillas XML para juntarlas posteriormente con datos y generar el PDF.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;font-family:georgia;" &gt;El inicio de todo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;Lo que vamos a hacer es por un lado, crearnos una &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-family:georgia;" &gt;plantilla XML con parámetros&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;, por otro lado, generar nuestros &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-family:georgia;" &gt;datos en formato XML&lt;/span&gt;&lt;span style="font-family:georgia;"&gt; (para poder guardarlos en base de datos) y finalmente, juntar las dos cosas y obtener, al vuelo, la &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-family:georgia;" &gt;plantilla con los datos en formato PDF&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;/div&gt;&lt;p  style="text-align: justify;font-family:georgia;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;El flujo de datos&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p face="georgia" style="text-align: justify;" class="MsoNormal"&gt;El funcionamiento del sistema de plantillas es el siguiente.&lt;/p&gt;&lt;p face="georgia" style="text-align: justify;" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxZHNqnSDI/AAAAAAAAAO0/sv4z-6qiI28/s1600-h/itext4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxZHNqnSDI/AAAAAAAAAO0/sv4z-6qiI28/s400/itext4.gif" alt="" id="BLOGGER_PHOTO_ID_5232154847560026162" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p face="georgia" style="text-align: justify;" class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p face="lucida grande" style="text-align: justify;" class="MsoNormal"&gt;&lt;!--[if gte vml 1]&gt;&lt;v:shapetype id="_x0000_t75" coordsize="21600,21600" spt="75" preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"&gt;  &lt;v:stroke joinstyle="miter"&gt;  &lt;v:formulas&gt;   &lt;v:f eqn="if lineDrawn pixelLineWidth 0"&gt;   &lt;v:f eqn="sum @0 1 0"&gt;   &lt;v:f eqn="sum 0 0 @1"&gt;   &lt;v:f eqn="prod @2 1 2"&gt;   &lt;v:f eqn="prod @3 21600 pixelWidth"&gt;   &lt;v:f eqn="prod @3 21600 pixelHeight"&gt;   &lt;v:f eqn="sum @0 0 1"&gt;   &lt;v:f eqn="prod @6 1 2"&gt;   &lt;v:f eqn="prod @7 21600 pixelWidth"&gt;   &lt;v:f eqn="sum @8 21600 0"&gt;   &lt;v:f eqn="prod @7 21600 pixelHeight"&gt;   &lt;v:f eqn="sum @10 21600 0"&gt;  &lt;/v:formulas&gt;  &lt;v:path extrusionok="f" gradientshapeok="t" connecttype="rect"&gt;  &lt;o:lock ext="edit" aspectratio="t"&gt; &lt;/v:shapetype&gt;&lt;v:shape id="_x0000_i1025" type="#_x0000_t75" style="'width:425.25pt;" ole=""&gt;  &lt;v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.emz" title=""&gt; &lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!--[if !vml]--&gt;&lt;br /&gt;&lt;!--[endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;o:oleobject type="Embed" progid="Visio.Drawing.11" shapeid="_x0000_i1025" drawaspect="Content" objectid="_1279718283"&gt;  &lt;/o:OLEObject&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style=";font-family:&amp;quot;;font-size:100%;"  &gt;&lt;span style="font-family:georgia;"&gt;Desde la página obtenemos los datos en XML y la plantilla, lo cual va en sesión a la página ImpresionPDF.aspx. Esa página se encarga de llamar a la clase ParseadorPDF.cs que es la que contiene la lógica de negocio para generar el PDF al vuelo. Esa clase devuelve un MemoryStream con el PDF a la página, la cual lo renderizará en pantalla.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);font-family:georgia;" &gt;La plantilla XML&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;El primer paso es generarnos la plantilla XML con los tags adecuados que entienda la librería. Para un ejemplo de los tags que se pueden utilizar, en la &lt;/span&gt;&lt;a style="font-family: georgia;" href="http://itextsharp.sourceforge.net/tutorial/ch07.html"&gt;ayuda &lt;/a&gt;&lt;span style="font-family:georgia;"&gt;nos ofrecen algunos &lt;/span&gt;&lt;a style="font-family: georgia;" href="http://itextsharp.sourceforge.net/examples/Chap0701.xml"&gt;ejemplos&lt;/a&gt;&lt;span style="font-family:georgia;"&gt;. Nosotros vamos a trabajar con el siguiente XML que es muy sencillo:&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/SHxX0c5D0bI/AAAAAAAAAOs/3ocJeajW6F0/s1600-h/itext1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/SHxX0c5D0bI/AAAAAAAAAOs/3ocJeajW6F0/s400/itext1.gif" alt="" id="BLOGGER_PHOTO_ID_5223146226463265202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:georgia;"&gt;En este informe utilizamos diferentes tags, como: table, row, cell, newline, itext(obligatorio al inicio y al fin) y en medio hemos introducido tags propios:nomAE, numAE, nomAl y dniAl. Estos serán los parámetros que se sustituirán posteriormente por los valores que le digamos. La librería itextsharp tiene un problema a la hora de parsear los XML en PDFs y es que &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-family:georgia;" &gt;NO PUEDE TENER ESPACIOS EN BLANCO DENTRO DE LOS TAGS TABLES&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;. Es decir, para generar una plantilla XML, no podemos indentarla, sino que tiene que ir como se muestra en la imagen o dará un error de ejecución.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);font-family:georgia;" &gt;Los datos a parsear&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;En este paso, lo que vamos a ver es cómo pasarle los datos que queremos que aparezcan en el informe a la librería para que los junte correctamente. &lt;/span&gt;&lt;link style="font-family: georgia;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;&lt;span style="font-family:georgia;"&gt;Le vamos a pasar un vector con dos dimensiones, en una dimensión irá un esquema XML con los datos a imprimir y en la otra irá la plantilla a utilizar. El esquema XML es como el siguiente:&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SJxaBRPo2BI/AAAAAAAAAO8/C8O7BoJ1VbE/s1600-h/itext2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_uUP4eiIAPJ8/SJxaBRPo2BI/AAAAAAAAAO8/C8O7BoJ1VbE/s400/itext2.gif" alt="" id="BLOGGER_PHOTO_ID_5232155844953036818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: georgia;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;A la hora de crear el documento veremos cómo crear este esquema XML para guardarlo en base de datos. Una vez recuperado el documento XML, la creación del vector es la siguiente:&lt;/p&gt;&lt;p style="font-family: lucida grande; text-align: justify;" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt; &lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxa0oposCI/AAAAAAAAAPE/o0j4YbRxeD0/s1600-h/itext3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxa0oposCI/AAAAAAAAAPE/o0j4YbRxeD0/s400/itext3.gif" alt="" id="BLOGGER_PHOTO_ID_5232156727409422370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: georgia;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;En el vector de objetos “datos” guardamos el XML y la plantilla correspondiente. Seguidamente llamamos a la pantalla ImpresionPDF.aspx que se encargará de generar la plantilla XML.&lt;/p&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;La página ImpresionPDF.aspx&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: lucida grande; text-align: justify;" class="MsoNormal"&gt;&lt;span style="font-family:georgia;"&gt;Esta página es la encargada de recibir los datos desde la sesión y llamar a la clase encargada de generar el PDF. Además de esto, obtiene de base de datos los márgenes a aplicar, las dimensiones del PDF y varios datos de formato propios de la plantilla. Una vez recuperados estos datos llama al método &lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="font-family:georgia;"&gt;GenerarPDF de la clase ParseadorPDF:&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxbS62_SwI/AAAAAAAAAPM/CqA6lgQC1WE/s1600-h/itext5.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxbS62_SwI/AAAAAAAAAPM/CqA6lgQC1WE/s400/itext5.gif" alt="" id="BLOGGER_PHOTO_ID_5232157247693343490" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: lucida grande;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;}  /* List Definitions */  @list l0 	{mso-list-id:654920845; 	mso-list-type:hybrid; 	mso-list-template-ids:1398806744 67764239 67764249 67764251 67764239 67764249 67764251 67764239 67764249 67764251;} @list l0:level1 	{mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt;} ol 	{margin-bottom:0cm;} ul 	{margin-bottom:0cm;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;El método devuelve un MemoryStream con el fichero PDF para ser renderizado. Veamos ahora cómo se produce el parseo real de los datos.&lt;/p&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;La clase ParseadorPDF.cs&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;Esta es la clase que se encarga de juntar las plantillas con sus respectivos datos. El flujo es el siguiente:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;1. Crear      el PDF global que va a ser devuelto y ponerle las dimensiones precisas:&lt;/p&gt;  &lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxcHzGvbUI/AAAAAAAAAPU/l_95ItU7dUQ/s1600-h/itext6.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxcHzGvbUI/AAAAAAAAAPU/l_95ItU7dUQ/s400/itext6.gif" alt="" id="BLOGGER_PHOTO_ID_5232158156144995650" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: georgia;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;}  /* List Definitions */  @list l0 	{mso-list-id:654920845; 	mso-list-type:hybrid; 	mso-list-template-ids:1398806744 67764239 67764249 67764251 67764239 67764249 67764251 67764239 67764249 67764251;} @list l0:level1 	{mso-level-tab-stop:45.0pt; 	mso-level-number-position:left; 	margin-left:45.0pt; 	text-indent:-18.0pt;} ol 	{margin-bottom:0cm;} ul 	{margin-bottom:0cm;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;&lt;span style="font-family:georgia;"&gt;2. &lt;span style="font-size:7;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-family:georgia;"&gt;Recorrer los datos y plantillas pasadas para ir tratando a cada una de ellas. Este método permite que se pasen a la vez varios XML de datos con varias plantillas en el mismo vector de objetos, por lo que lo primero es ir recorriendo las diferentes plantillas. Para cada XML de datos realizamos una conversión a un vector de objects con los datos que es lo que entiende el método:&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxcSLGDHgI/AAAAAAAAAPc/IH2ZgEoIOOc/s1600-h/itext7.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxcSLGDHgI/AAAAAAAAAPc/IH2ZgEoIOOc/s400/itext7.gif" alt="" id="BLOGGER_PHOTO_ID_5232158334383234562" border="0" /&gt;&lt;/a&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: lucida grande;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;}  /* List Definitions */  @list l0 	{mso-list-id:654920845; 	mso-list-type:hybrid; 	mso-list-template-ids:1398806744 67764239 67764249 67764251 67764239 67764249 67764251 67764239 67764249 67764251;} @list l0:level1 	{mso-level-tab-stop:45.0pt; 	mso-level-number-position:left; 	margin-left:45.0pt; 	text-indent:-18.0pt;} ol 	{margin-bottom:0cm;} ul 	{margin-bottom:0cm;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:georgia;"&gt;3. Para cada plantilla con sus datos los juntamos en un PDF temporal que es guardado en una ruta temporal y posteriormente anexado al PDF global que se creó al inicio. En esta parte es donde se realiza la unión real de los datos, creando un hashtable que enlaza cada parámetro con su valor y llamando al método Parse de la librería PDF:  &lt;/span&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: georgia;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;}  /* List Definitions */  @list l0 	{mso-list-id:654920845; 	mso-list-type:hybrid; 	mso-list-template-ids:1398806744 67764239 67764249 67764251 67764239 67764249 67764251 67764239 67764249 67764251;} @list l0:level1 	{mso-level-tab-stop:45.0pt; 	mso-level-number-position:left; 	margin-left:45.0pt; 	text-indent:-18.0pt;} ol 	{margin-bottom:0cm;} ul 	{margin-bottom:0cm;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;&lt;br /&gt;&lt;/div&gt;&lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxcfJgO_vI/AAAAAAAAAPk/jxnq_6LFJ2Q/s1600-h/itext8.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxcfJgO_vI/AAAAAAAAAPk/jxnq_6LFJ2Q/s400/itext8.gif" alt="" id="BLOGGER_PHOTO_ID_5232158557294493426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;4. Una vez realizado el parseo, lo que tenemos que hacer es eliminar los ficheros temporales que hemos ido creando en el proceso. Estos ficheros se encuentran guardados en la variable subFicheros.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;p  class="MsoNormal" style="font-family:georgia;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p face="georgia" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;El método ParsearDatos&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p style="font-family: georgia;" class="MsoNormal"&gt;Este método es el encargado de crear un hashtable que enlace cada parámetro con su valor. Lo primero es crear el hashtable y asignarle los primeros valores fijos:&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SJxcppWuORI/AAAAAAAAAPs/9tR7BNE13T0/s1600-h/itext9.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_uUP4eiIAPJ8/SJxcppWuORI/AAAAAAAAAPs/9tR7BNE13T0/s400/itext9.gif" alt="" id="BLOGGER_PHOTO_ID_5232158737643223314" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: lucida grande;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:&amp;quot;;font-size:12;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:georgia;"&gt;Seguidamente, para cada parámetro, tendremos que unirlo con su parámetro y asignarle un XMLPeer correcto:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: lucida grande;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxc0fTiFhI/AAAAAAAAAP0/IRc9ufrpXYY/s1600-h/itext10.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxc0fTiFhI/AAAAAAAAAP0/IRc9ufrpXYY/s400/itext10.gif" alt="" id="BLOGGER_PHOTO_ID_5232158923924051474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link style="font-family: lucida grande;" rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: georgia;" class="MsoNormal"&gt;Dependiendo del tipo de parámetro que sea será tratado de una forma o de otra, lo que rellenamos en el método es la propiedad peer.Content con el valor del parámetro y si le queremos incluir más atributos rellenamos la propiedad peer.AddValue.&lt;/p&gt;&lt;p style="font-family: georgia;" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="font-family: georgia;" class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p style="font-family: georgia;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;El método ConcatenarPaginas&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p style="font-family: georgia;" class="MsoNormal"&gt;Este método se encarga de unir las páginas de los PDF temporales que creamos con la del PDF global que será devuelto a la capa de presentación. El código de este método es el siguiente:&lt;/p&gt;&lt;p face="lucida grande" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxc_lusYNI/AAAAAAAAAP8/5lGjeSrYhPI/s1600-h/itext11.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_uUP4eiIAPJ8/SJxc_lusYNI/AAAAAAAAAP8/5lGjeSrYhPI/s400/itext11.gif" alt="" id="BLOGGER_PHOTO_ID_5232159114627145938" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 10"&gt;&lt;meta name="Originator" content="Microsoft Word 10"&gt;&lt;link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:hyphenationzone&gt;21&lt;/w:HyphenationZone&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:12.0pt; 	font-family:"Times New Roman"; 	mso-fareast-font-family:"Times New Roman";} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 3.0cm 70.85pt 3.0cm; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tabla normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} &lt;/style&gt; &lt;![endif]--&gt;  &lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: lucida grande;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;b&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;El final&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;Bueno, con esto termino el artículo. Espero haberos dado una idea inicial de cómo realizar un motor de plantillas basado en XML para la librería itextsharp. No he podido explicar el funcionamiento completo porque eso exigiría muchísimo tiempo pero creo haber ahondado bastante para que podáis seguir vosotros.&lt;/p&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt;  &lt;/div&gt;&lt;p style="font-family: georgia; text-align: justify;" class="MsoNormal"&gt;Como siempre, para cualquier duda que os surja aquí estoy.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-5665931870877814458?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/5665931870877814458/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=5665931870877814458' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5665931870877814458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5665931870877814458'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/07/motor-de-informes-dinmicos-con.html' title='Motor de Informes Dinámicos con itextsharp (II)'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_uUP4eiIAPJ8/SJxZHNqnSDI/AAAAAAAAAO0/sv4z-6qiI28/s72-c/itext4.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-855382809029505321</id><published>2008-05-27T13:00:00.004Z</published><updated>2008-07-07T22:41:22.381Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='EHAS'/><category scheme='http://www.blogger.com/atom/ns#' term='telecomunicaciones rurales'/><category scheme='http://www.blogger.com/atom/ns#' term='redes inalámbricas'/><category scheme='http://www.blogger.com/atom/ns#' term='máquina virtual'/><title type='text'>Diseño de redes inalámbricas con Radio Mobile (II)</title><content type='html'>&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;Actualización (30/05/07):&lt;/span&gt; Si alguien instaló en su Ubuntu VirtualBox cuando escribí la entrada, es posible que unos días después, tras actualizar su distribución notara que VirtualBox dejaba de funcionar dando un error de que el driver no estaba presente. Se debía a que hubo una actualización del kernel a la versión 2.6.24-17, para la que los módulos de VirtualBox ya no valían (se podía arreglar simplemente arrancando con el kernel anterior). Pues bien, a quienes les haya pasado ésto les recomiendo que vuelvan a actualizar, pues a partir de hoy ya están disponibles los módulos de VirtualBox para el nuevo kernel, veréis que ya os funcionará sin problemas en su última versión.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;En la &lt;a href="http://nidea-soluciones.blogspot.com/2008/05/diseo-de-redes-inalmbricas-con-radio.html"&gt;anterior entrada&lt;/a&gt; ya vimos cómo instalar una máquina virtual &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; sobre la que instalaremos ahora nuestro software de &lt;a href="http://www.cplus.org/rmw/english1.html"&gt;Radio Mobile&lt;/a&gt;, pero antes de ello vamos a depurar un poquito más nuestra máquina virtual para no tener que andar pulsando el "botón de anfitrión" cada vez que queremos usar el ratón sobre nuestro linux, y para permitir la compartición de carpetas entre el sistema host y el sistema anfitrión, que trabajar en la misma máquina y tener que andar con una memoria usb para pasar ficheros dentro de la misma máquina es un poco triste :).&lt;br /&gt;&lt;br /&gt;Abrimos nuevamente nuestra máquina virtual (Aplicaciones -&gt; Herramientas del Sistema -&gt; VirtualBox OSE), la iniciamos (botón "Iniciar"). Cuando la máquina se haya iniciado, pinchamos en el menú "Dispositivos" y pulsamos sobre "Instalar aplicaciones del huésped". Os dirá que no se puede encontrar la imágen .iso de las aplicaciones del huésped, que si queréis descargarla, así que le decimos que la descargue, y luego cuando nos pregunte si queremos montarla, le decimos que sí. Ahora se nos abrirá la pantallita de instalación típica de windows:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SDk7GweezFI/AAAAAAAAAWk/NgzxakzkS_Q/s1600-h/aplicaciones_huesped.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SDk7GweezFI/AAAAAAAAAWk/NgzxakzkS_Q/s320/aplicaciones_huesped.png" alt="" id="BLOGGER_PHOTO_ID_5204255831681322066" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/SDk7ZQeezGI/AAAAAAAAAWs/82J6rBhtlc4/s1600-h/aplicaciones_huesped2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/SDk7ZQeezGI/AAAAAAAAAWs/82J6rBhtlc4/s320/aplicaciones_huesped2.png" alt="" id="BLOGGER_PHOTO_ID_5204256149508901986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Y cuando se nos haya instalado (necesita reiniciar), lo primero que notaréis es que ya no es necesario que pulsemos el CTRL DRCHO para sacar el ratón de la máquina virtual, sino que la ventana se comporta como una más de nuestro Linux y símplemente cuando pasamos el ratón por encima de ella, el ratón se pasa a comportar como si fuera el ratón del sistema Windows, permitiéndonos pulsar sobre sus menús y demás, ésto lo hace todo más cómodo. Además, también hemos instalado en el huésped la aplicación que nos permite la compartición de carpetas entre la máquina y nuestro sistema, pero para ésto aún tendremos que hacer un retoque chiquitín en nuestro sistema anfitrión, que explico a continuación.&lt;br /&gt;&lt;br /&gt;Lo primero es crear la carpeta que vamos a usar para intercambiar ficheros entre los dos sistemas (ej: /home/tu_usuario/Intercambio). Una vez creada, la compartimos, que es tan fácil como irse con el Nautilus hasta la carpeta, darle al botón derecho sobre ella y decir "Opciones de Compartición". Os dirá, si es la primera vez que compartís archivos, que tiene que instalar la compartición de ficheros por samba, pero no os preocupéis, le dais a que lo instale y después de instalarlo será necesario que cerréis sesión y volváis a abrirla para que funcione. Una vez hecho esto volvéis a la carpeta a su "Opciones de Compartición" y pincháis en compartirla, quedando así:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDlCcgeezHI/AAAAAAAAAW0/MbXfZxBvqSM/s1600-h/compartir.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDlCcgeezHI/AAAAAAAAAW0/MbXfZxBvqSM/s320/compartir.png" alt="" id="BLOGGER_PHOTO_ID_5204263901924871282" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Le decís "Crear compartición" y os dirá...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDlChgeezII/AAAAAAAAAW8/oslzOhmB0uo/s1600-h/compartir2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDlChgeezII/AAAAAAAAAW8/oslzOhmB0uo/s320/compartir2.png" alt="" id="BLOGGER_PHOTO_ID_5204263987824217218" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Pues bien, pulsad en "Añadir los permisos automáticamente", y listo, la carpeta se os debería mostrar en el nautilus de esta guisa...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SDlDSweezJI/AAAAAAAAAXE/dDmTApklqQI/s1600-h/compartir3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SDlDSweezJI/AAAAAAAAAXE/dDmTApklqQI/s320/compartir3.png" alt="" id="BLOGGER_PHOTO_ID_5204264833932774546" border="0" /&gt;&lt;/a&gt;...lo que os hará saber que está todo en orden.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDn5aAeezKI/AAAAAAAAAXM/6fywnRPbUsA/s1600-h/unidad_red.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDn5aAeezKI/AAAAAAAAAXM/6fywnRPbUsA/s320/unidad_red.png" alt="" id="BLOGGER_PHOTO_ID_5204465069603081378" border="0" /&gt;&lt;/a&gt;Ahora ya para poder compartir ficheros desde uno al otro lado, nos vamos a la máquina virtual (Windows XP) y ahí pinchamos en "Inicio -&gt; ejecutar". Escribimos "cmd" y pulsamos "enter". Lo que nos saldrá es un interprete de comandos de windows. Ahí escribiremos "net use Z: \\127.0.0.1\Intercambio". Nos dirá que se ha terminado la operación con éxito. Ahora ya podremos ver nuestra carpeta en windows como si se tratase de una unidad distinta (que hemos llamado Z:) mientras en GNU/Linux sigue siendo nuestra carpeta /home/tu_usuario/Intercambio. ¿A que mola?&lt;br /&gt;&lt;br /&gt;Bien, una vez configurado todo esto, llegó la hora de instalar el Radio Mobile, nos vamos a &lt;a href="http://www.cplus.org/rmw/download/download.html"&gt;la página de descarga&lt;/a&gt;, lo descargamos y seguimos los pasos que ahí nos pone, que son pocos y fáciles, y los cuento a continuación:&lt;br /&gt;1. Descargamos el fichero que se enlaza en el paso 1 (step 1) y que viene a ser una librería. Después pinchamos, decimos un sitio donde queremos que se descombrima y luego vamos ahí y lo ejecutamos para que se instale en nuestro sistema.&lt;br /&gt;2. Creamos la carpeta C:\Radio_Mobile&lt;br /&gt;3. Descargamos el fichero que pone en "step 3" y lo descomprimimos dentro de la carpeta Radio_Mobile que creamos en el paso anterior.&lt;br /&gt;4. Hacemos lo mismo con el fichero que se enlaza en "step 4".&lt;br /&gt;5. Descargamos el fichero que se enlaza para el caso de lengua castellana (spanish language), y lo descomprimimos dentro, como en los pasos anteriores.&lt;br /&gt;6. Creamos una carpeta que se llame por ejemplo "mapas" donde meteremos los mapas que nos descarguemos.&lt;br /&gt;7. Descargamos y descomprimimos, como antes, el fichero que está enlazado en "File wmap.zip".&lt;br /&gt;8. Ejecutamos el fichero "rmUpdatespa.exe" dentro de nuestra carpeta Radio_Mobile (veréis una pantallita como la que sigue).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoDBweezLI/AAAAAAAAAXU/uCrwbhQrA8M/s1600-h/actualiza_radiomobile.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoDBweezLI/AAAAAAAAAXU/uCrwbhQrA8M/s320/actualiza_radiomobile.png" alt="" id="BLOGGER_PHOTO_ID_5204475648107531442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Le damos a Siguiente, actualizamos y listo.&lt;br /&gt;&lt;br /&gt;¡Bien! Ya tenemos instalado el software. De hecho, si queréis podéis probarlo ejecutando el fichero "rmwspa.exe", os saldrá algo como...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDoDYQeezMI/AAAAAAAAAXc/uL75Ez7JRYE/s1600-h/radio_mobile.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDoDYQeezMI/AAAAAAAAAXc/uL75Ez7JRYE/s320/radio_mobile.png" alt="" id="BLOGGER_PHOTO_ID_5204476034654588098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Pero aquí no acaba todo, porque ahora hay que descargarse los mapas SRTM (mapas topográficos). En realidad Radio Mobile admite varios tipos distintos de formatos de mapas, pero los SRTM son los que para la región de latinoamérica que queremos tratar ofrecen mayor precisión, y para nosotros que el mapa sea preciso será extremadamente vital, pensad que si uno diseña una red perfectamente, se va a la selva, instala equipos, antenas y torres y resulta que luego la señal no llega al otro extremo, el problema es bastante serio (obviamente en la realidad no son estas las únicas pruebas que se hacen antes de instalar los equipos), pero está claro que el software no nos sirve si no usamos mapas medianamente precisos.&lt;br /&gt;&lt;br /&gt;Estos mapas SRTM se pueden conseguir de varios sitios, yo os contaré el proceso descargándolos del servidor ftp de la NASA, para lo que os recomiendo que os descarguéis e instaléis el &lt;a href="http://filezilla-project.org/"&gt;filezilla&lt;/a&gt; en vuestra máquina virtual de windows (a nosotros nos interesará el "Filezilla Client" puesto que lo que queremos es un cliente FTP, no un servidor).&lt;br /&gt;&lt;br /&gt;Ahora abrimos el Radio Mobile (para agilizar el proceso os recomiendo que creéis un acceso directo al fichero "rmwspa.exe" en el escritorio). Y buscamos las coordenadas aproximadas de nuestra zona de trabajo. Para ello pinchamos en "Archivo -&gt; Propiedades del mapa", y ahí le damos a "Seleccionar un nombre de ciudad". Buscamos la ciudad de Iquitos, que es la ciudad más grande de la selva peruana y que está bastante cerca de nuestra zona de actuación. así, se colocarán automáticamente las coordenadas de esta ciudad (Latitud: -3,85 ; Longitud: -73,22). Así ya nos podemos hacer una idea de que si la región del Napo está ligeramente al noroeste de Iquitos, necesitaremos los mapas correspondientes latitudes más o menos de entre 0 y 5 grados sur y de longitudes entre 68 y 78 grados oeste (para todo esto google earth os puede ayudar bastante, yo he elegido un cuadrante amplio que más o menos encuadra todo lo que podríamos necesitar para nuestro diseño).&lt;br /&gt;&lt;br /&gt;Y bien, ahora que ya tenemos eso claro abrimos el Filezilla que antes habíamos instalado. En el campo de servidor copiaremos...&lt;br /&gt;ftp://e0srp01u.ecs.nasa.gov/srtm/version2/SRTM3/South_America&lt;br /&gt;...y le damos a conexión rápida.&lt;br /&gt;Como véis lo que vamos a hacer es buscar dentro de la sección que se ha abierto a la derecha los mapas que corresponden a las latitudes y longitudes que buscamos y copiarlos a nuestra carpeta de "mapas" que nos creamos antes. Para ello simplemente buscamos desde el fichero S01W068.hgt.zip al fichero S01W078.hgt.zip y los arrastramos a nuestra carpeta mapas que tendremos abierta en la sección de la izquierda, luego hacemos los propio con los que van de S02W068.hgt.zip a S02W078.hgt.zip, con los de S03W068.hgt.zip a S03W078.hgt.zip, con los de S04W068.hgt.zip a S04078.hgt.zip y finalmente con los que van de S05W068.hgt.zip a S05W078.hgt.zip y así habremos cubierto el cuadrante que necesitábamos.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;Nota:&lt;/span&gt; Cuando lo que queramos sea descargar mapas de otra zona, podéis acceder al servidor entrando con el Filezilla en la dirección ftp://e0srp01u.ecs.nasa.gov/srtm/version2/SRTM3/ y buscando por la región que queráis acceder&lt;/blockquote&gt;&lt;br /&gt;Ahora en el Radio Mobile pinchamos en "Archivo -&gt; Propiedades del mapa", volvemos a establecer Iquitos como centro del mapa, en Ancho y Alto pondremos 800 x 600, seleccionamos la ubicación de los mapas y establecemos que son de tipo SRTM, ponemos una altitud de 200 km para tener bastante plano y pinchamos en "Extraer".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoVmweezOI/AAAAAAAAAXs/h2QaQgclHeg/s1600-h/estableciendo_mapa.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoVmweezOI/AAAAAAAAAXs/h2QaQgclHeg/s320/estableciendo_mapa.png" alt="" id="BLOGGER_PHOTO_ID_5204496074971991266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;El mapa resultante...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoU8weezNI/AAAAAAAAAXk/E6w4DydGWhw/s1600-h/primer_mapa.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDoU8weezNI/AAAAAAAAAXk/E6w4DydGWhw/s320/primer_mapa.png" alt="" id="BLOGGER_PHOTO_ID_5204495353417485522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;...está centrado en la ciudad de Iquitos y abarca hasta la unión del Napo con el Amazonas, así que vemos que realmente, si nuestra red está en el río napo, tendremos que subir nuestro mapa más hacia arriba, pero bueno, empezaremos centrando el mapa en uno de los puntos y ya iremos afinando. Claro que eso será ya en la siguiente entrega de esta saga de entradas, que pa una entrada ésto ya se está convirtiendo en demasiao largo :).&lt;br /&gt;&lt;br /&gt;De toas formas, las coordenadas de nuestros puntos, por si alguno/a quiere ir probando a averiguar como funciona la cosa, son:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cabo Pantoja:&lt;/span&gt; 0º58'13,26''S  75º10'29,21''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Torres Causana:&lt;/span&gt; 1º6'16,53''S  75º0'14,17''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tempestad:&lt;/span&gt; 1º17'22,81''S  74º52'27,42''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tupac Amaru:&lt;/span&gt; 1º21'46,55''S  74º44'42,89''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Angoteros:&lt;/span&gt; 1º34'9,54''S  74º36'20,17''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Campo Serio:&lt;/span&gt; 1º47'35,48''S  74º42'50,09''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Rumi Tuni:&lt;/span&gt; 2º3'16,22''S  74º26'9,30''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; San Rafael:&lt;/span&gt; 2º22'1,43''S  74º6'42,91''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Copal Urco:&lt;/span&gt; 2º20'23,41''S  73º47'26,23''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Santa Clotilde:&lt;/span&gt; 2º29'22,07''S  73º40'41,02''O&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Tacsha Curaray:&lt;/span&gt; 2º48'47,46''S  73º32'27,30''O&lt;br /&gt;&lt;br /&gt;Saludetes chavalinos y chavalinas y hasta dentro de poquito.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-855382809029505321?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/855382809029505321/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=855382809029505321' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/855382809029505321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/855382809029505321'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/05/diseo-de-redes-inalmbricas-con-radio_27.html' title='Diseño de redes inalámbricas con Radio Mobile (II)'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_Odz8IS0Tz3k/SDk7GweezFI/AAAAAAAAAWk/NgzxakzkS_Q/s72-c/aplicaciones_huesped.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-2306519448870960579</id><published>2008-05-23T00:00:00.000Z</published><updated>2008-05-24T11:55:14.156Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='EHAS'/><category scheme='http://www.blogger.com/atom/ns#' term='telecomunicaciones rurales'/><category scheme='http://www.blogger.com/atom/ns#' term='redes inalámbricas'/><category scheme='http://www.blogger.com/atom/ns#' term='máquina virtual'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Diseño de redes inalámbricas con Radio Mobile (I)</title><content type='html'>¡Buenas de nuevo!&lt;br /&gt;&lt;br /&gt;Como lo prometido es deuda, y después de las entradas "facilonas" en las que sólo colgaba 2 libros para su descarga (que son muy buenos, de veras); ahora me voy a mojar un poquillo más y en esta entrada me he propuesto diseñar una red con Radio Mobile. Para demostrar su aplicación, vamos a hacer como ejemplo una red ya existente que se diseñó con este software, y que viene a ser la red que la &lt;a href="http://www.ehas.org/"&gt;Fundación EHAS&lt;/a&gt; instaló en marzo del año pasado a lo largo del río Napo, en los distritos de Napo y Torres Causana, provincia de Maynas, región de Loreto, en el Perú amazónico. Se trata de una red orientada a salud que se pretende (y de hecho lo está haciendo desde ya hace un año) que de los servicios de telefonía, correo electrónico, internet y diversos de telemedicina (en esto último la red aún no está lo suficientemente explotada y se está trabajando en buscar soluciones de telemedicina útiles y aplicables en estos entornos) para los centros de salud de una región aislada del planeta. Los beneficiarios directos del proyecto serán por tanto los centros de salud, que si tuviéramos delante el árbol de soluciones de &lt;a href="http://nidea-soluciones.blogspot.com/2007/03/gestin-de-proyectos-de-cooperacin-al.html"&gt;El Marco Lógico&lt;/a&gt; de nuestro proyecto, nos daríamos cuenta de que repercuten directamente en la mejora de las condiciones de la población local.&lt;br /&gt;&lt;br /&gt;Para situarnos un poco más, os pongo el mapa de direccionamiento de la red del que nosotros nos encargaríamos de diseñar todos los enlaces inalámbricos.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SC_yHffxmFI/AAAAAAAAAUU/LQnRF_NDBsc/s1600-h/maparednapo.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SC_yHffxmFI/AAAAAAAAAUU/LQnRF_NDBsc/s320/maparednapo.png" alt="" id="BLOGGER_PHOTO_ID_5201642305163991122" border="0" /&gt;&lt;/a&gt;Llegado este punto, alguno pensará "...y si se trata de enlaces inalámbricos WiFi, ¿para qué #$%/&amp;amp; hay que usar un software de diseño? yo en mi casa pongo mi router a funcionar y a ¡ale! ¡a correr!". Pues bien, eso está genial para enlaces cortos típicos de redes locales WiFi, que no superan los 300m en el mejor de los casos, pero los enlaces que vemos en el mapa que arriba pongo, llegan a tener hasta 42km entre nodos, en una región tropical selvática con la atenuación de señal que humedad, selva y demás asuntos introducen en nuestros balances de enlace, y todo ello sin dejar de ser WiFi (aunque como ya veremos en futuras entradas, para el correcto funcionamiento de estos enlaces hace falta hacer algunos truquillos con el driver &lt;a href="http://madwifi.org/"&gt;Madwifi&lt;/a&gt; para tarjetas con chipsets atheros sobre linux que rompen ligeramente el estándar WiFi sin abandonar la interoperabilidad con cualquier otro dispositivo que cumpla el estándar 802.11).&lt;br /&gt;&lt;br /&gt;Por otras entradas del blog, muchos/as ya sabréis que soy un linuxero empedernido, así que usar software diseñado para windows habitualmente me produce urticaria, pero dado el buen uso que puede tener este software y para que me duela menos, explicaré el proceso sobre una "&lt;a href="http://www.ubuntu.com/getubuntu/download"&gt;Ubuntu 8.04&lt;/a&gt;", la última versión disponible, instalando una máquina virtual "VirtualBox" sobre la que se instalará a su vez un Windows XP. Si me da el venazo, igual os explico también cómo hacerlo directamente sobre Linux usando el emulador "Wine".&lt;br /&gt;&lt;br /&gt;Lo primero que vamos a hacer es descargarnos la máquina virtual "VirtualBox" y para ello nos vamos a &lt;a href="http://www.virtualbox.org/"&gt;su página web&lt;/a&gt; y nos &lt;a href="https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=innotek-1.6-G-F@CDS-CDS_SMI"&gt;descargamos el software&lt;/a&gt; (decir que Sun Microsystems anunció en febrero de este año la adquisición de la empresa responsable de VirtualBox, que es Innotek GmbH, por lo que el software ha pasado de llamarse "Innotek VirtualBox" a ser ahora "Sun xVM VirtualBox 1.6", ya sabéis, chorradas empresariales de nomenclatura. Los que tengáis la antigua máquina virtual, os vale lo mismo, pero probablemente la página sea alojada dentro de poco en los servidores de Sun). Para la descarga seleccionamos nuestra plataforma (Ubuntu 8.04 x86), marcamos el tradicional cuadro de aceptar licencia "I agree" (cualquier día me da el venazo y me leo una de estas licencias pa saber lo que estoy aceptando :) ) y pinchamos en el botón "Continue". La cosa no podía ser más sencillica. Nos sale un paquete .deb para descargar. Lo descargamos corriendo antes de que nadie nos lo quite :D. Para instalarlo, nos bastará un "sudo dpkg -i nombre_paquete.deb" en un terminal.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDdwTAeey1I/AAAAAAAAAUk/hj1Q5e2bMm4/s1600-h/synaptic.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDdwTAeey1I/AAAAAAAAAUk/hj1Q5e2bMm4/s320/synaptic.png" alt="" id="BLOGGER_PHOTO_ID_5203751366297570130" border="0" /&gt;&lt;/a&gt;Pero para quien eso de abrir una consola le de urticaria, siempre está la opción de nuestro amigo el synaptics (gestor de paquetes). Se abre, se busca por virtualbox, se marca el paquete para su instalación y luego se pulsa en "Aplicar". No tiene pérdida.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDdyegeey2I/AAAAAAAAAUs/JnSuZJM_kc8/s1600-h/virtualbox.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDdyegeey2I/AAAAAAAAAUs/JnSuZJM_kc8/s320/virtualbox.png" alt="" id="BLOGGER_PHOTO_ID_5203753762889321314" border="0" /&gt;&lt;/a&gt;Después de la instalación de VirtualBox, ya lo tenemos en Aplicaciones -&gt; Herramientas del sistema -&gt; VirtualBox OSE. Pues bien, pulsamos en él para abrirlo. Como se podía intuir, nuestra intención será crear una nueva máquina virtual, así que pinchamos en el botón de "Nueva" y comenzamos a configurarla.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo primero es un típico "Siguiente". Luego damos un nombre a nuestra máquina y seleccionamos el tipo de sistema operativo que instalaremos en ella (en nuestro caso un Windows XP...¡uy! ¡qué dolor ver esas letras juntas!). Como parece que le he pillado el gustillo a esto del botón "impr pant" del teclado.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDd1zAeey3I/AAAAAAAAAU0/XfrYMbwR_2w/s1600-h/nombre_maquina.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDd1zAeey3I/AAAAAAAAAU0/XfrYMbwR_2w/s320/nombre_maquina.png" alt="" id="BLOGGER_PHOTO_ID_5203757413611522930" border="0" /&gt;&lt;/a&gt;Pulsamos en "Siguiente" y nos preguntará la memoria base que queremos destinar a la máquina virtual. La mínima son 192MB, pero para darle más soltura a la cosa, yo le he puesto 512MB, dependerá de cuánta tengáis. Si le ponéis muy poca irá más lento, pero por contra no os comerá terreno a vuestro preciado GNU/Linux. Pulsamos en "Siguiente", y ahora nos toca crear un disco duro para nuestra máquina virtual. Bueno, aquí tenemos la opción de que el disco duro tenga un tamaño estático o un tamaño dinámico (que crecerá cuando se vaya agotando). Ésto se traducirá en un fichero .vdi, que luego podremos borrar o copiar a nuestro antojo para trasladar nuestra máquina virtual a otro sitio. Yo he decidido usarlo de 10GB iniciales y dinámico...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDd44Aeey4I/AAAAAAAAAU8/9Eqs9srTbeM/s1600-h/disco_duro.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDd44Aeey4I/AAAAAAAAAU8/9Eqs9srTbeM/s320/disco_duro.png" alt="" id="BLOGGER_PHOTO_ID_5203760798045752194" border="0" /&gt;&lt;/a&gt;Ya sabéis..."Siguiente" y "Finalizar" cuando os lo pida.&lt;br /&gt;&lt;br /&gt;De vuelta al proceso de creación de la máquina, ahora seleccionamos el disco duro que acabamos de crear como primario de nuestra nueva máquina y pinchamos en "Terminar". Y ahí está, ya tenemos a nuestra pequeña creada, a la espera de ser configurada y luego instalada.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDd54geey5I/AAAAAAAAAVE/ueiYOr_Mm5c/s1600-h/creada.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDd54geey5I/AAAAAAAAAVE/ueiYOr_Mm5c/s320/creada.png" alt="" id="BLOGGER_PHOTO_ID_5203761906147314578" border="0" /&gt;&lt;/a&gt;Hagamos antes de la instalación algunos retoques de configuración, son poquitos. Con la máquina seleccionada, pinchamos en el botón de "Configuración". Primero, si disponemos de suficiente memoria de vídeo, le daremos un poco más de holgura a la máquina, para que nuestro Radio Mobile se mueva agusto.&lt;br /&gt;&lt;br /&gt;Ahora es buen momento para introducir en vuestra lectora de CD o DVD el disco de instalación de un Windows XP (no seré yo quien os diga si el disco ha de ser original o pirata :) ). Nos vamos a la sección de "CD/DVD-ROM" y marcamos la casilla de "Monta la unidad de CD/DVD".&lt;br /&gt;&lt;br /&gt;Lo siguiente será activar el audio. Nos vamos a la sección "Audio" y marcamos "Habilitar Audio". Finalmente pincharemos en "Ok" y ya está, ya estamos listos para instalar un sistema operativo peor que el anfitrión, pero que nos dará la posibilidad de diseñar nuestra red inalámbrica mediante el software de Radio Mobile. Para arrancar la máquina, ahora ya sí, pinchamos en el botón "Iniciar" con nuestra máquina seleccionada.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SDfo8Qeey6I/AAAAAAAAAVM/2usiZkKSlOY/s1600-h/arranque1.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SDfo8Qeey6I/AAAAAAAAAVM/2usiZkKSlOY/s320/arranque1.png" alt="" id="BLOGGER_PHOTO_ID_5203884016362507170" border="0" /&gt;&lt;/a&gt;Al darle a "Iniciar", nos sale un cuadrito que nos familiariza con el funcionamiento de VirtualBox. Se nos recuerda que cuando pulsemos sobre la ventana de la máquina virtual (mientras no esté instalado algo que haremos más tarde), la máquina huésped (Windows) se hará con el control de nuestro teclado hasta que pulsemos la "Tecla anfitrión", que viene a ser por defecto el CTRL DRCHO. Cuando pulsemos esa tecla, nuestro teclado y ratón actuarán sobre nuestro sistema anfitrión (GNU/Linux Ubuntu).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;...y hecho ésto...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDfquAeey7I/AAAAAAAAAVU/o27rP89vU4Q/s1600-h/error.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDfquAeey7I/AAAAAAAAAVU/o27rP89vU4Q/s320/error.png" alt="" id="BLOGGER_PHOTO_ID_5203885970572626866" border="0" /&gt;&lt;/a&gt;¡¡ALARM, ALARM!!&lt;br /&gt;&lt;br /&gt;La maquinilla nos chilla que nanai, pero afortunadamente el mensaje de error contiene la solución del problema así que no tendréis mucho problema en solucionarlo. Sólo tenemos que instalar el paquete que nos pide. Lo hacemos con "sudo aptitude install virtualbox-ose-modules-2.6.24-16-generic" en un terminal. Lo siguiente será introducir a nuestro usuario dentro del grupo "vboxusers", y para ello nos vamos a "Sistema -&gt; Administración -&gt; Usuarios y Grupos". Ahí pinchamos en "Gestionar Grupos", luego seleccionamos el grupo vboxusers y marcamos nuestro usuario &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDf1PAeey9I/AAAAAAAAAVk/_TRgcN6EbjY/s1600-h/usuariogrupo2.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDf1PAeey9I/AAAAAAAAAVk/_TRgcN6EbjY/s320/usuariogrupo2.png" alt="" id="BLOGGER_PHOTO_ID_5203897532624587730" border="0" /&gt;&lt;/a&gt;para que se agregue al grupo. Cerramos y ya lo tenemos, pero para que el usuario sea efectivamente agregado, tendremos que reiniciar. Para quien prefiera hacer las cosas desde un terminal, se puede agregar un usuario al grupo vboxusers sólo escribiendo "sudo adduser &lt;tu_usuario&gt; vboxusers" (mucho más rápido, ¿eh?).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Luego pulsamos en "Iniciar" y como tenemos introducido el cd de instalación de Windows, el resto podemos decir que ya es historia, la vieja historia de la instalación de un Windows y que resumiré en capturas:&lt;br /&gt;&lt;br /&gt;&lt;/tu_usuario&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDf_Ygeey-I/AAAAAAAAAVs/RWxmqk8izxg/s1600-h/instalacion1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDf_Ygeey-I/AAAAAAAAAVs/RWxmqk8izxg/s320/instalacion1.png" alt="" id="BLOGGER_PHOTO_ID_5203908690949622754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDf_jAeey_I/AAAAAAAAAV0/mSAqURzVC3w/s1600-h/instalar2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDf_jAeey_I/AAAAAAAAAV0/mSAqURzVC3w/s320/instalar2.png" alt="" id="BLOGGER_PHOTO_ID_5203908871338249202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/SDf_vQeezAI/AAAAAAAAAV8/OTjYIBD-GbY/s1600-h/instalacion3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/SDf_vQeezAI/AAAAAAAAAV8/OTjYIBD-GbY/s320/instalacion3.png" alt="" id="BLOGGER_PHOTO_ID_5203909081791646722" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/SDf_4weezBI/AAAAAAAAAWE/QSolOH2pt4Y/s1600-h/instalar4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/SDf_4weezBI/AAAAAAAAAWE/QSolOH2pt4Y/s320/instalar4.png" alt="" id="BLOGGER_PHOTO_ID_5203909245000403986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDgACQeezCI/AAAAAAAAAWM/LtSHUYMXR64/s1600-h/instalar5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDgACQeezCI/AAAAAAAAAWM/LtSHUYMXR64/s320/instalar5.png" alt="" id="BLOGGER_PHOTO_ID_5203909408209161250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/SDgARweezDI/AAAAAAAAAWU/4YyESYBk5hc/s1600-h/instalar6.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/SDgARweezDI/AAAAAAAAAWU/4YyESYBk5hc/s320/instalar6.png" alt="" id="BLOGGER_PHOTO_ID_5203909674497133618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/SDgAjQeezEI/AAAAAAAAAWc/2LqzD1gsnso/s1600-h/instalar7.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/SDgAjQeezEI/AAAAAAAAAWc/2LqzD1gsnso/s320/instalar7.png" alt="" id="BLOGGER_PHOTO_ID_5203909975144844354" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Y ... ¡voilà! Ya tenemos el windows sobre el que instalaremos nuestro Radio Mobile, pero la instalación del software os la contaré en la siguiente entrada. Ni que decir tiene que lo que tenemos ya instalado es un windows plenamente funcional, así que se le puede instalar cualquier cosa que se pudiera instalar sobre un sistema no virtualizado (aunque parece ser que algunas cosas como la aceleración gráfica aún no está muy conseguida).&lt;br /&gt;&lt;br /&gt;¡Hasta la próxima entrada!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-2306519448870960579?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/2306519448870960579/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=2306519448870960579' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2306519448870960579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/2306519448870960579'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/05/diseo-de-redes-inalmbricas-con-radio.html' title='Diseño de redes inalámbricas con Radio Mobile (I)'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_Odz8IS0Tz3k/SC_yHffxmFI/AAAAAAAAAUU/LQnRF_NDBsc/s72-c/maparednapo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-8681430754834595204</id><published>2008-05-17T08:37:00.005Z</published><updated>2008-05-18T09:24:18.605Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='EHAS'/><category scheme='http://www.blogger.com/atom/ns#' term='telecomunicaciones rurales'/><category scheme='http://www.blogger.com/atom/ns#' term='libro'/><category scheme='http://www.blogger.com/atom/ns#' term='Creative Commons'/><category scheme='http://www.blogger.com/atom/ns#' term='redes inalámbricas'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Libro "Redes Inalámbricas en los Países en Desarrollo"</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://isf.uc3m.es/descargas_publicas/Documentacion_Cooperacion/TICs/Libro_Redes_Inalambricas_en_los_Paises_en_Desarrollo.pdf"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/SC6aqffxmEI/AAAAAAAAAUM/gPl6nxFwJWI/s320/redes_inalambricas_paises_desarrollo.jpg" alt="" id="BLOGGER_PHOTO_ID_5201264674459457602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Buenas a todos de nuevo, aquí os dejo otro libro más sobre redes inalámbricas, éste un poco más antiguo, surge del proyecto &lt;a href="http://www.wndw.net/"&gt;WNDW&lt;/a&gt; (Wireless Networking in the Developing World) y os puede ayudar a informaros más a fondo sobre estos temas. Espero que os sea de utilidad. Lo podéis &lt;a href="http://isf.uc3m.es/descargas_publicas/Documentacion_Cooperacion/TICs/Libro_Redes_Inalambricas_en_los_Paises_en_Desarrollo.pdf"&gt;descargar&lt;/a&gt; igual que el anterior porque también está &lt;a href="http://creativecommons.org/licenses/by-sa/2.5/deed.es"&gt;licenciado bajo Creative Commons&lt;/a&gt;. Si preferís &lt;a href="http://isf.uc3m.es/descargas_publicas/Documentacion_Cooperacion/TICs/Libro_Redes_Inalambricas_en_Paises_en_Desarrollo_ingles.pdf"&gt;descargaros la segunda edición en inglés&lt;/a&gt;, también la tenéis aquí disponible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-8681430754834595204?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/8681430754834595204/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=8681430754834595204' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8681430754834595204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8681430754834595204'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/05/libro-redes-inalmbricas-en-los-pases-en.html' title='Libro &quot;Redes Inalámbricas en los Países en Desarrollo&quot;'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_Odz8IS0Tz3k/SC6aqffxmEI/AAAAAAAAAUM/gPl6nxFwJWI/s72-c/redes_inalambricas_paises_desarrollo.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-1952816266388565322</id><published>2008-05-12T16:50:00.004Z</published><updated>2008-05-18T09:23:58.766Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='EHAS'/><category scheme='http://www.blogger.com/atom/ns#' term='telecomunicaciones rurales'/><category scheme='http://www.blogger.com/atom/ns#' term='libro'/><category scheme='http://www.blogger.com/atom/ns#' term='Creative Commons'/><category scheme='http://www.blogger.com/atom/ns#' term='redes inalámbricas'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Libro "Redes Inalámbricas para Zonas Rurales"</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://isf.uc3m.es/descargas_publicas/Documentacion_Cooperacion/TICs/Libro_Redes_Inalambricas_para_zonal_Rurales.pdf"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/SCh0c_fxmDI/AAAAAAAAAUE/aPuvv4wZYm8/s320/Libro_Redes_Inalambricas.png" alt="" id="BLOGGER_PHOTO_ID_5199533811229104178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;El &lt;a href="http://gtr.telecom.pucp.edu.pe/"&gt;Grupo de Telecomunicaciones Rurales&lt;/a&gt; de la &lt;a href="http://www.pucp.edu.pe/"&gt;PUCP&lt;/a&gt; (Universidad que es contraparte local de los proyectos que la &lt;a href="http://www.ehas.org/"&gt;Fundación EHAS&lt;/a&gt; desarrolla en Perú, como el que os relataba en el blog "&lt;a href="http://cooperantesuc3m.blogspot.com/"&gt;Cooperante no hay camino...&lt;/a&gt;"), ha publicado un libro que trata en profundidad el despliegue de redes inalámbricas para zonas rurales de países en desarrollo. Podéis &lt;a href="http://isf.uc3m.es/descargas_publicas/Documentacion_Cooperacion/TICs/Libro_Redes_Inalambricas_para_zonal_Rurales.pdf"&gt;descargar el libro si lo deseáis&lt;/a&gt; ya que está licenciado bajo Creative Commons. Os lo recomiendo, hay mucho conocimiento ahí condensado.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-1952816266388565322?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/1952816266388565322/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=1952816266388565322' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1952816266388565322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/1952816266388565322'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/05/libro-redes-inalmbricas-para-zonas.html' title='Libro &quot;Redes Inalámbricas para Zonas Rurales&quot;'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_Odz8IS0Tz3k/SCh0c_fxmDI/AAAAAAAAAUE/aPuvv4wZYm8/s72-c/Libro_Redes_Inalambricas.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7297125973233840325</id><published>2008-03-28T16:11:00.019Z</published><updated>2009-08-10T09:35:03.395Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='itextsharp'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Motor de informes dinámicos con iTextSharp (I)</title><content type='html'>&lt;blockquote&gt;Actualización: he colgado los códigos del proyecto para que podáis jugar con ellos y utilizarlos en vuestros proyectos. Los podéis descargar desde &lt;a href="http://www.nidea-soluciones.com/descargas/PruebaITextSharp.rar"&gt;aquí&lt;/a&gt; &lt;/blockquote&gt;&lt;br /&gt;&lt;div style="TEXT-ALIGN: justify"&gt;&lt;/div&gt;&lt;div style="TEXT-ALIGN: justify"&gt;Buenas de nuevo a todo el mundo que lee este blog (cada día sois más, lo que es de agradecer). He estado muy ocupado últimamente montando mi propio motor de informes dinámicos utilizando la librería &lt;a href="http://itextsharp.sourceforge.net/"&gt;iTextSharp&lt;/a&gt; para generación de documentos PDF.&lt;br /&gt;&lt;br /&gt;La idea inicial era poder disponer (dentro de una aplicación ASP.NET) de un sistema de impresión de informes con tres características principales:&lt;br /&gt;&lt;/div&gt;&lt;ol style="TEXT-ALIGN: justify"&gt;&lt;li&gt;Impresión de informes al vuelo en PDF&lt;/li&gt;&lt;li&gt;Disponer de plantillas en XML para mezclar datos de base de datos y mostrarlos en PDF (también al vuelo).&lt;/li&gt;&lt;li&gt;Poder modificar las plantillas XML desde un editor&lt;/li&gt;&lt;/ol&gt;&lt;div style="TEXT-ALIGN: justify"&gt;Con estos requisitos me puse manos a la obra con iText# (una librería excelente) y os explico cómo lo plantee por si os sirve para vuestros desarrollos o como punto de partida para otras cosas.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(204,153,51)"&gt;Impresión de Informes al vuelo en PDF&lt;/span&gt;&lt;br /&gt;Ésta fue la parte más fácil y más complicada a la vez. La más complicada porque me pegué de lleno con la librería y la más fácil cuando aprendí los entresijos de la misma. Para imprimir informes en PDF al vuelo basta con seguir el siguiente ciclo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/R-4ilEssvvI/AAAAAAAAANU/TI2fuV0an1w/s1600-h/PDF1.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183118241461747442" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp0.blogger.com/_uUP4eiIAPJ8/R-4ilEssvvI/AAAAAAAAANU/TI2fuV0an1w/s400/PDF1.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La idea consiste en generar los datos a imprimir en la pagina aspx donde esté el usuario. Esos datos los &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;guardamos en la sesión&lt;/span&gt; y llamamos a la pantalla &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;MostrarInforme.aspx&lt;/span&gt;. Esta pantalla recupera los datos de la sesión y se los pasa a la clase &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(51,102,102)"&gt;GeneradorPDF.cs&lt;/span&gt; que se encarga de crear el PDF (en memoria) en base a los datos pasados. El método que genera el PDF devuelve un objeto del tipo &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(204,153,51)"&gt;MemoryStream &lt;/span&gt;a la página MostrarInforme.aspx, el cual es renderizado en pantalla mediante un &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;Response.OutputStream.Write()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Dicho así, la verdad es que no aclaro demasiado el tema, así que vamos a ver el código que siempre ayuda más.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(204,153,51)"&gt;El Código&lt;/span&gt;&lt;br /&gt;Lo primero fue plantearme el alcance de esta parte del motor de informes. Lo que queríamos era poder imprimir &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(255,102,0)"&gt;cualquier tabla&lt;/span&gt; de &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(255,102,0)"&gt;cualquier pantalla&lt;/span&gt; con &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(255,102,0)"&gt;cualquier tipo de campos&lt;/span&gt; y &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(255,102,0)"&gt;número&lt;/span&gt; de una forma común y fácil. Con este objetivo en mente, lo inicial fue definir las variables de sesión en las que se iban a pasar los datos desde las páginas a la pantalla &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;MostrarInforme.aspx&lt;/span&gt;:&lt;br /&gt;&lt;/div&gt;&lt;ul style="TEXT-ALIGN: justify"&gt;&lt;li&gt;DataTable con los datos&lt;/li&gt;&lt;li&gt;DataTable con los nombres de las columnas de la tabla que se quieren imprimir y el nombre que se le pone a cada una de ellas en el informe.&lt;/li&gt;&lt;li&gt;Orientación de la página para poder imprimir en apaisado y en vertical&lt;/li&gt;&lt;li&gt;Anchos (en porcentaje) de las columnas que se van a imprimir&lt;/li&gt;&lt;li&gt;Nombre del listado que aparecerá en la cabecera&lt;/li&gt;&lt;/ul&gt;&lt;div style="TEXT-ALIGN: justify"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(102,51,51)"&gt;1. Preparar la Impresión&lt;/span&gt;&lt;br /&gt;Con estas variables de sesión tenemos información suficiente para poder imprimir el informe. Un ejemplo de cómo se preparan las variables de sesión en una pantalla es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/R-4n6UssvwI/AAAAAAAAANc/oWwHLtAnsOY/s1600-h/PDF2.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183124104092106498" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp1.blogger.com/_uUP4eiIAPJ8/R-4n6UssvwI/AAAAAAAAANc/oWwHLtAnsOY/s400/PDF2.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En este método lo que hago es crear las variables de sesión necesarias (casi todo está con enumerados y struct).&lt;br /&gt;&lt;/div&gt;&lt;ol style="TEXT-ALIGN: justify"&gt;&lt;li&gt;TABLA_DATOS: Para el Datatable con todos los datos.&lt;/li&gt;&lt;li&gt;ORIENTACION_PAGINA: para decirle si queremos imprimir en vertical o en horizontal.&lt;/li&gt;&lt;li&gt;CAMPOS_A_IMPRIMIR: para indicar aquellas columnas del datatable de datos que queremos imprimir y el nombre que queremos que aparezca en la cabecera de dicha columna en el informe. Aquí utilizo un datatable tipado DtCamposListadoPDF.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;ANCHOS_DE_COLUMNA: array de enteros con los anchos de cada una de las columnas (en el mismo orden) que he introducido en CAMPOS_A_IMPRIMIR.&lt;/li&gt;&lt;li&gt;TITULO_LISTADO: Título que va a llevar el informe.&lt;/li&gt;&lt;/ol&gt;&lt;div style="TEXT-ALIGN: justify"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(102,51,51)"&gt;2. Llamar a MostrarInforme.aspx&lt;/span&gt;&lt;br /&gt;Una vez que tenemos las variables de sesión, llamaremos a la pantalla MostrarInforme.aspx desde nuestra aplicación. Para abrirla hay varias opciones (Javascript, inyectando código). A mi lo que me interesaba era que se mostrará el PDF en una nueva ventana, así que llamo a la página desde Javascript, con un window.open.&lt;br /&gt;&lt;br /&gt;También se puede hacer con:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/R-4qrUssvxI/AAAAAAAAANk/UykT0NtZOC0/s1600-h/PDF3.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183127144928952082" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp1.blogger.com/_uUP4eiIAPJ8/R-4qrUssvxI/AAAAAAAAANk/UykT0NtZOC0/s400/PDF3.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;El código de &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;MostrarInforme.aspx&lt;/span&gt; es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4rbkssvyI/AAAAAAAAANs/5iFcFyDpeo8/s1600-h/PDF4.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183127973857640226" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4rbkssvyI/AAAAAAAAANs/5iFcFyDpeo8/s400/PDF4.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Todo se realiza en el Page_Load() porque vamos a devolver un Stream al navegador. Lo primero que hacemos es recuperar las variables de sesion que la página ha creado. Obtengo también la ruta de una imagen que va a aparecer en plan logo en los informes para pasarla al método.&lt;br /&gt;Una vez obtenidos los datos llamo al método estático &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;GenerarListado&lt;/span&gt; que va a devolver un &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(204,153,51)"&gt;MemoryStream &lt;/span&gt;con el PDF.&lt;br /&gt;&lt;br /&gt;Con el MemoryStream lo que hago es renderizarlo en la pantalla mediante el objeto Response. Vamos a ver cómo genero el PDF al vuelo.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(102,51,51)"&gt;3. Generar el PDF&lt;/span&gt;&lt;br /&gt;El método GenerarListado de la clase GeneradorPDF es el que realmente se encarga de crear dinámicamente el informe PDF.&lt;br /&gt;&lt;br /&gt;Los using que tenemos que utilizar son:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4tpkssvzI/AAAAAAAAAN0/jar9ebiaKsw/s1600-h/pdf6.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183130413399064370" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4tpkssvzI/AAAAAAAAAN0/jar9ebiaKsw/s400/pdf6.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En la primera parte del método definimos el objeto &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;Document &lt;/span&gt;que va a contener el PDF, la orientación y enlazamos el objeto &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;MemoryStream&lt;/span&gt; con el objeto &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;Document &lt;/span&gt;para indicarle que vamos a realizar las operaciones en memoria.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/R-4uKEssv0I/AAAAAAAAAN8/4geA_mi7Oko/s1600-h/pdf5.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183130971744812866" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp0.blogger.com/_uUP4eiIAPJ8/R-4uKEssv0I/AAAAAAAAAN8/4geA_mi7Oko/s400/pdf5.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En segundo lugar llamamos al método &lt;span style="FONT-WEIGHT: bold; COLOR: rgb(0,153,0)"&gt;IncluirElementosComunes&lt;/span&gt; para crear la cabecera del informe, el título y para que incluya el logo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4urkssv1I/AAAAAAAAAOE/5rjINkYJAT4/s1600-h/pdf7.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183131547270430546" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R-4urkssv1I/AAAAAAAAAOE/5rjINkYJAT4/s400/pdf7.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El código de este método es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/R-40J0ssv2I/AAAAAAAAAOM/OUWx_O-x3GU/s1600-h/pdf8.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183137564519612258" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp3.blogger.com/_uUP4eiIAPJ8/R-40J0ssv2I/AAAAAAAAAOM/OUWx_O-x3GU/s400/pdf8.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En este método creamos la cabecera del informe, una tabla con el logo en una celda y con el título del listado y la fecha de impresión en la otra. Además, en este método abrimos la escritura en el documento con la instrucción docPdf.Open().&lt;br /&gt;&lt;br /&gt;Volviendo al método general, las siguientes instrucciones lo que van a hacer es ir creando una tabla, con tantas columnas como le hemos pasado en sesión y la vamos rellenando con los datos del Datatable de datos.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/R-43H0ssv3I/AAAAAAAAAOU/mcWM735x2KY/s1600-h/pdf9.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183140828694757234" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp3.blogger.com/_uUP4eiIAPJ8/R-43H0ssv3I/AAAAAAAAAOU/mcWM735x2KY/s400/pdf9.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Vamos iterando sobre los datatables e incluyendo la información. En esta parte, cada uno dará al informe el aspecto que más le guste. Al final incluimos la tabla en el documento PDF.&lt;br /&gt;&lt;br /&gt;Para finalizar lo que tenemos que hacer es capturar los errores, cerrar el PDF y devolver el stream.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R-43pkssv4I/AAAAAAAAAOc/zWFI-aFJt8Y/s1600-h/pdf10.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183141408515342210" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R-43pkssv4I/AAAAAAAAAOc/zWFI-aFJt8Y/s400/pdf10.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Una muestra de un informe en PDF generado por esta función es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R-44vkssv5I/AAAAAAAAAOk/8GgW_fhX4oQ/s1600-h/pdf11.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5183142611106185106" style="FLOAT: left; MARGIN: 0pt 10px 10px 0pt; CURSOR: pointer" alt="" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R-44vkssv5I/AAAAAAAAAOk/8GgW_fhX4oQ/s400/pdf11.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: rgb(204,153,51)"&gt;Final&lt;/span&gt;&lt;br /&gt;En la próxima entrega veremos como realizar las plantillas XML con parámetros y cómo mezclarlas con datos de bases de datos de una forma dinámica. Finalmente, en la tercera entrega veremos como editar las plantillas y cómo crearnos traductores XML y HTML para dichas plantillas.&lt;br /&gt;&lt;br /&gt;Espero que os haya interesado este primer artículo y que lo aprovechéis para vuestros desarrollos. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7297125973233840325?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7297125973233840325/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7297125973233840325' title='13 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7297125973233840325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7297125973233840325'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/03/motor-de-informes-dinmicos-con.html' title='Motor de informes dinámicos con iTextSharp (I)'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_uUP4eiIAPJ8/R-4ilEssvvI/AAAAAAAAANU/TI2fuV0an1w/s72-c/PDF1.gif' height='72' width='72'/><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7615234249946379094</id><published>2008-03-04T19:40:00.018Z</published><updated>2008-03-05T09:33:58.819Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='certificados'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='seguridad'/><title type='text'>Firmar una llamada SOAP con C# y ASP.NET</title><content type='html'>&lt;span style="font-size:100%;"&gt;En este artículo voy a intentar explicar cómo firmar una llamada SOAP utilizando la extensión para servicios web WS 3.0 de Microsoft. Como siempre, lo primero es un poco de teoría y luego veremos cómo pasar esta teoría a la práctica.&lt;br /&gt;&lt;br /&gt;Es recomendable que os leáis el &lt;a href="http://nidea-soluciones.blogspot.com/2008/01/usar-certificados-de-cliente-en-una.html"&gt;artículo anterior&lt;/a&gt; a este sobre certificados digitales de la FNMT puesto que haremos uso de lo que en él comentaba.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:100%;" &gt;1. Teoría&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;La idea es poder realizar una llamada a un servicio web externo (una administración, por ejemplo) asegurando que el contenido de la misma no ha sido manipulado en el camino. El ejemplo más claro es el de una aplicación web que se integra con la administración, por lo que tiene que firmar las peticiones con el certificado de la FNMT del cliente que en ese momento este usando la aplicación.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/R82pjKEdBqI/AAAAAAAAAMU/v0Odxmrf-Jg/s1600-h/XMLSignature1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/R82pjKEdBqI/AAAAAAAAAMU/v0Odxmrf-Jg/s400/XMLSignature1.gif" alt="" id="BLOGGER_PHOTO_ID_5173977968382117538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La idea es que nosotros seamos una especie de pasarela de certificados de nuestros clientes a los servicios web de la administración o de otro sitio. Para realizar esto tendremos que firmar las llamadas SOAP con el certificado usando el estándar XMLSignature.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:100%;" &gt;2. ¿Cómo lo hacemos?&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Para hacerlo, lo primero que tenemos que hacer es descargarnos las extensiones de Servicios Web de Microsoft (WSE 3.0) que podéis encontrar en la dirección:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=018a09fd-3a74-43c5-8ec1-8d789091255d&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyID=018a09fd-3a74-43c5-8ec1-8d789091255d&amp;amp;displaylang=en&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Una vez instalado en nuestro equipo, tendremos una nueva opción en Visual Studio para el trabajo con las extensiones de Web Services.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);font-size:100%;" &gt;¿Cómo funciona WSE 3.0?&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;El centro del tema este son las políticas y los filtros. Cuando realizamos una llamada a un servicio web, ésta es interceptada por una clase que define lo que hay que realizar con dicha llamada antes de que salga. Cuando recibimos una respuesta, la respuesta es interceptada igualmente, y lo mismo pasa cuando definimos los servicios web.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/R82ss6EdBrI/AAAAAAAAAMc/5LDqaQW2qM4/s1600-h/XMLSignature2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/R82ss6EdBrI/AAAAAAAAAMc/5LDqaQW2qM4/s400/XMLSignature2.gif" alt="" id="BLOGGER_PHOTO_ID_5173981434420725426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Donde nosotros vamos a trabajar es en la clase de políticas de seguridad, que será donde se firme la petición.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;font-size:100%;" &gt;Paso 1: Habilitar nuestro web para WSE3.0&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Lo primero es habilitar nuestro sitio web para que utilice WSE3.0. Al habilitarlo, las clases proxy que se creen estarán preparadas para las extensiones de WSE. Tendremos que crearnos un sitio web en el Visual Studio y en las propiedades del sitio web veremos cómo aparece una nueva opción "WSE Settings 3.0". Al pinchar se abre la ventana:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R82txqEdBsI/AAAAAAAAAMk/eMNPnNeV7DE/s1600-h/XMLSignature3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R82txqEdBsI/AAAAAAAAAMk/eMNPnNeV7DE/s400/XMLSignature3.gif" alt="" id="BLOGGER_PHOTO_ID_5173982615536731842" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Marcamos la primera opción para habilitar las opciones del cliente. La segunda opción es para habilitar las opciones cuando nosotros somos el servicio web.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;font-size:100%;" &gt;Paso 2: Agregar la referencia a WSE&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Agregar una referencia a la librería Microsoft.Web.Services3 a nuestro proyecto.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;font-size:100%;" &gt;Paso 3: Agregar la referencia web&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Agregaremos la referencia web al servicio con el que nos queramos comunicar.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;font-size:100%;" &gt;Paso 4: Crear la política de seguridad&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Vamos a crear la clase que controla la entrada y salida de mensajes SOAP desde el cliente. Esta clase tiene que heredar de &lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;Securit&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;yPolicyAs&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;sertion&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R82xJqEdBuI/AAAAAAAAAM0/zFvCBs5S2do/s1600-h/XMLSignature4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R82xJqEdBuI/AAAAAAAAAM0/zFvCBs5S2do/s400/XMLSignature4.gif" alt="" id="BLOGGER_PHOTO_ID_5173986326388475618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;La clase tiene cuatro métodos, uno para cada situación: salida/entrada para el cliente y salida/entrada para el servicio. A nosotros el que nos interesa es el de la salida para el cliente, el resto lo ponemos a null.&lt;br /&gt;&lt;br /&gt;La sección de imports es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R85loaEdBwI/AAAAAAAAANE/xK0HSglCrLM/s1600-h/XMLSignature6.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R85loaEdBwI/AAAAAAAAANE/xK0HSglCrLM/s400/XMLSignature6.gif" alt="" id="BLOGGER_PHOTO_ID_5174184766762452738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En el constructor le pasamos el certificado del cliente (luego veremos cómo llamamos a esta clase) para poder utilizarlo en el método de salida del cliente. En este método lo que hacemos es instanciar una nueva clase que hereda de SendSecurityFilter que es la que realmente firma la petición:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/R82xq6EdBvI/AAAAAAAAAM8/la7YtVj95CQ/s1600-h/XMLSignature5.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/R82xq6EdBvI/AAAAAAAAAM8/la7YtVj95CQ/s400/XMLSignature5.gif" alt="" id="BLOGGER_PHOTO_ID_5173986897619126002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);font-size:100%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En esta clase lo que hacemos es obtener el token del certificado y añadirle la firma al mensaje SOAP, haciendo override del método SecureMessage. Con esto tenemos prácticamente hecho todo.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 153, 51); font-weight: bold;"&gt;Paso 5: Realizar la llamada&lt;/span&gt;&lt;br /&gt;Nos creamos una página aspx desde la que vamos a realizar la llamada. Lo primero será obtener el certificado del cliente (ver el &lt;a href="http://nidea-soluciones.blogspot.com/2008/01/usar-certificados-de-cliente-en-una.html"&gt;artículo anterior&lt;/a&gt;), una vez obtenido tendremos que asociar la política que hemos definido con la llamada al servicio web:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/R85nJ6EdBxI/AAAAAAAAANM/TNEJ_Gwdbcs/s1600-h/XMLSignature7.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/R85nJ6EdBxI/AAAAAAAAANM/TNEJ_Gwdbcs/s400/XMLSignature7.gif" alt="" id="BLOGGER_PHOTO_ID_5174186441799698194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 102);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;En este caso, he creado un servicio web con un método llamado "CalculaSuma" el cual suma dos números que se le pasan. En un botón llamado "btnInvocar" de la página le asocio el código para llamar al servicio web. Lo que hacemos es instanciar la clase proxy que se creó al agregar la referencia web y le asociamos la política que hemos creado.&lt;br /&gt;&lt;br /&gt;Al realizar la llamada, la política intercepta el mensaje de salida, ejecuta el método "SecureMessage()" y firma la petición. Podemos activar el modo Trace con el asistente de WSE y ver la salida para comprobar que se ha firmado la petición, incluyéndose un nuevo elemento en la llamada SOAP llamado &lt;/span&gt;&lt;signature&gt;&lt;span style="font-size:100%;"&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:100%;" &gt;3. Fin&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Espero que os haya gustado y servido este post. No ha sido muy exhaustivo pero como punto de partida para la utilización de XMLSignature en SOAP puede ser bueno.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/signature&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7615234249946379094?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7615234249946379094/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7615234249946379094' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7615234249946379094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7615234249946379094'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/03/firmar-una-llamada-soap-con-c-y-aspnet.html' title='Firmar una llamada SOAP con C# y ASP.NET'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_uUP4eiIAPJ8/R82pjKEdBqI/AAAAAAAAAMU/v0Odxmrf-Jg/s72-c/XMLSignature1.gif' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-5686099060199782123</id><published>2008-01-27T17:50:00.000Z</published><updated>2008-01-27T17:56:07.362Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='retorno'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Documental EHAS</title><content type='html'>Buenas de nuevo a todos/as&lt;br /&gt;&lt;br /&gt;De nuevo estoy aquí ya de vuelta de la selva pa daros el coñazo con nuevas entradas. Por el momento estoy en un momento muy liado hasta finales de febrero, pero quería dejar constancia de que a partir de ahora retomaré el hábito de escribir alguna entrada cada cierto tiempo. Y para que no sea una entrada vacía, aquí os dejo un documental sobre la Fundación EHAS (Enlace Hispano-Americano de Salud) que lleva ya 10 años trabajando en proyectos de cooperación para el desarrollo en Perú, Colombia y Cuba, aplicando para ello su investigación en Tecnologías de la Información y la Comunicación adaptadas a estos entornos. Ellos son los culpables de que haya dejado de escribir este tiempo :). Espero que os guste.&lt;br /&gt;&lt;br /&gt;&lt;embed style="width: 400px; height: 326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-5503913434637125776&amp;amp;hl=es" flashvars=""&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;Saludos de nuevo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-5686099060199782123?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/5686099060199782123/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=5686099060199782123' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5686099060199782123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5686099060199782123'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/01/documental-ehas.html' title='Documental EHAS'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7513305907194466466</id><published>2008-01-16T19:49:00.000Z</published><updated>2008-01-22T19:57:25.189Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='certificados'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><category scheme='http://www.blogger.com/atom/ns#' term='seguridad'/><title type='text'>Usar certificados de cliente de la FNMT en una Aplicación Web</title><content type='html'>Mucho tiempo ha pasado desde la última entrada, pero entre que hemos estado muy ocupados y la pereza que da ponerse de nuevo a escribir, pues, han pasado tres meses (o más). Sin embargo, un nuevo reto se me planteó y tras sudar sangre para resolverlo lo comparto con vosotros. El tema de este post es: &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;¿Cómo usar certificados de la FNMT (Fábrica Nacional de Moneda y Timbre) en nuestra web?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;Existe poquísima información al respecto en Internet, muchos posts de gente, mucha historieta pero nada concreto. Voy a intentar, por lo tanto, dar las instrucciones para configurar un servidor de internet (en mi caso IIS, aunque la configuración es similar para el resto) para poder pedir al usuario que utilice un certificado emitido por la FNMT.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Paso I: La Seguridad&lt;/span&gt;&lt;br /&gt;Si no tenemos una conexión https con SSL, GAME OVER, fin de la partida. Es requisito indispensable comunicarnos con el cliente mediante una conexión cifrada para poder interactuar con los certificados. Pero, ¿cómo lo hacemos para conseguir un certificado?. En desarrollo podemos seguir los siguientes pasos (en producción necesitareis un certificado emitido por una CA Root reconocida):&lt;br /&gt;&lt;br /&gt;Existen muchos sitios en internet donde se describe este proceso, os pongo esta url donde explican como generar nuestro propio certificado con OpenSSL:&lt;br /&gt;&lt;a href="http://www.locualo.net/programacion/activar-ssl-iis-certificado-digital-prueba/00000079.aspx"&gt;http://www.locualo.net/programacion/activar-ssl-iis-certificado-digital-prueba/00000079.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Paso II: La Teoría&lt;/span&gt;&lt;br /&gt;Vamos a ver un poco de la teoría para saber cómo funciona el tema de los certificados. Una vez que sepamos como funciona, entenderemos los pasos a dar. El circuito de los certificados es el siguiente:&lt;br /&gt;&lt;br /&gt;1. El cliente accede a la url https://.... (para la cual es necesario un certificado de cliente)&lt;br /&gt;2. El servidor envía su certificado al cliente para establecer el canal seguro. El cliente debe confiar en la entidad que ha generado ese certificado y comprobar que es válido. En caso de no confiar aparecerá un mensaje en el explorador indicándonoslo (la mayoría de la gente no lo lee).&lt;br /&gt;3. Una vez que el cliente ha &lt;span style="color: rgb(0, 153, 0); font-weight: bold;"&gt;confiado &lt;/span&gt;en el servidor, se establece el canal seguro.&lt;br /&gt;4. El servidor tiene configurado que para el recurso que intenta ver el cliente es necesario  que presente un certificado de cliente, emitido por una &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;entidad certificadora en la que él confíe&lt;/span&gt; y además que está en la &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;lista de los certificados admitidos para el recurso&lt;/span&gt; en cuestión.&lt;br /&gt;5. El explorador del cliente recibe estas condiciones del servidor y muestra una ventana con los certificados instalados que cumplan los requisitos del servidor.&lt;br /&gt;6. El usuario elige su certificado y éste es mandado al servidor.&lt;br /&gt;7. El servidor comprueba la lista de revocación de certificados de la entidad que emitió el certificado para ver si sigue siendo válido.&lt;br /&gt;8. En caso que el certificado sea válido, podremos acceder al recurso y en la &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;sesión &lt;/span&gt;tendremos guardado el certificado para usarlo.&lt;br /&gt;&lt;br /&gt;En la siguiente imagen os muestro el flujo:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZAAM0myEI/AAAAAAAAALs/5-7qJagPR_Y/s1600-h/Certificados1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZAAM0myEI/AAAAAAAAALs/5-7qJagPR_Y/s400/Certificados1.gif" alt="" id="BLOGGER_PHOTO_ID_5158380795385530434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Paso II&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;I: La Confianza&lt;/span&gt;&lt;br /&gt;Como habéis podido observar, la clave del asunto es la confianza entre los diferentes elementos (cliente y servidor). Vamos a ver cómo configurar nuestro servidor para: 1) requerir el certificado del cliente y 2)confiar en la fnmt para que acepte sus certificados.&lt;br /&gt;&lt;br /&gt;Para requerir el certificado del cliente iremos al "Administrador de Servicios de IIS", buscaremos el recurso, sitio web o directorio virtual que necesitará certificado y pulsamos en "Propiedades" del menú contextual. En la pestaña "Seguridad de Directorios" pulsamos sobre el botón "Modificar" de la parte inferior. Nos aparecerá la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZChM0myFI/AAAAAAAAAL0/Cf9He90nR2g/s1600-h/Certificados2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZChM0myFI/AAAAAAAAAL0/Cf9He90nR2g/s400/Certificados2.gif" alt="" id="BLOGGER_PHOTO_ID_5158383561344469074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Marcaremos la opción "Requerir Canal Seguro" y "Requerir Certificados de Cliente". Pulsamos sobre Aceptar y hemos terminado. Ahora el IIS espera un certificado del cliente para acceder al recurso, sin embargo, todavía no le hemos dicho que debe confiar en la FNMT como entidad certificadora.&lt;br /&gt;&lt;br /&gt;Para &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;confiar en la FNMT&lt;/span&gt;, tendremos que abrir una consola mmc (Ejecutar--&gt; mmc), Archivo--&gt;Agregar o Quitar Complemento. En la pantalla que aparece pulsaremos de nuevo sobre Agregar y seleccionaremos el complemento "Certificados":&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZD2M0myGI/AAAAAAAAAL8/LGb4uSJ1KbM/s1600-h/Certificados3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZD2M0myGI/AAAAAAAAAL8/LGb4uSJ1KbM/s400/Certificados3.gif" alt="" id="BLOGGER_PHOTO_ID_5158385021633349730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Pulsamos sobre "Agregar", seleccionamos la opción "Mi Cuenta de usuario" y cerramos la pantalla de agregar complementos. En la consola mmc, expandimos "Entidades emisoras raíz de confianza--&gt;Certificados" y buscamos a la FNMT:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/R5ZEt80myHI/AAAAAAAAAME/t76uDPqPQpA/s1600-h/Certificados4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/R5ZEt80myHI/AAAAAAAAAME/t76uDPqPQpA/s400/Certificados4.gif" alt="" id="BLOGGER_PHOTO_ID_5158385979411056754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En caso que no esté, tendremos que importarlo. Lo primero será conseguir la definición del certificado de la FNMT. La podéis conseguir desde aquí:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.cert.fnmt.es/content/pages_std/certificados/FNMTClase2CA.cer"&gt;http://www.cert.fnmt.es/content/pages_std/certificados/FNMTClase2CA.cer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Guardamos el fichero .cer en nuestro servidor y en la consola mmc pulsamos con el botón derecho sobre "Certificados" y elegimos "Todas las tareas--&gt;Importar". Saltará un asistente para importar un certificado, seleccionaremos el fichero que nos acabamos de descargar y siguiente hasta el final.&lt;br /&gt;&lt;br /&gt;Una vez importado, veremos las propiedades del certificado y habilitaremos la opción &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;"Autenticación del Cliente"&lt;/span&gt;. De esta forma habilitamos a los certificados de la FNMT para que sirvan como certificados de cliente.&lt;br /&gt;&lt;br /&gt;Con esto hemos dado nuestra confianza a la FNMT como CA Root, sin embargo, todavía no funciona porque tenemos que incluir a la FNMT como entidad válida para nuestro recurso, en la CTL (Certificate Trusted List). Para ello, volvemos a la consola del IIS y nos vamos a las propiedades del&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt; sitio web&lt;/span&gt; en el que esté el recurso del certificado. Seleccionamos la pestaña "Seguridad de Directorios" y pulsamos sobre el botón "Modificar" de la parte inferior. Aparecerá la pantalla siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/R5ZIfs0myII/AAAAAAAAAMM/xpeXrm0pKd8/s1600-h/Certificados5.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/R5ZIfs0myII/AAAAAAAAAMM/xpeXrm0pKd8/s400/Certificados5.gif" alt="" id="BLOGGER_PHOTO_ID_5158390132644432002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En la parte inferior tenemos la lista de certificados de confianza, pulsamos sobre "Modificar" y en la lista que aparece, pulsamos sobre "Agregar desde el almacén" e incluimos el de la FNMT. Pulsamos "Siguiente" hasta el final y ya tenemos todo hecho.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Paso IV: Final&lt;/span&gt;&lt;br /&gt;Ya tenemos nuestro entorno habilitado para utilizar certificados de cliente. En producción tendremos que tener un certificado emitido por una entidad reconocida, pero el resto es igual.&lt;br /&gt;&lt;br /&gt;Espero que os haya aclarado las ideas y os haya servido.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7513305907194466466?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7513305907194466466/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7513305907194466466' title='35 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7513305907194466466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7513305907194466466'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2008/01/usar-certificados-de-cliente-en-una.html' title='Usar certificados de cliente de la FNMT en una Aplicación Web'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_uUP4eiIAPJ8/R5ZAAM0myEI/AAAAAAAAALs/5-7qJagPR_Y/s72-c/Certificados1.gif' height='72' width='72'/><thr:total>35</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-5727460260108582813</id><published>2007-09-06T22:13:00.000Z</published><updated>2007-09-08T00:12:19.039Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='blog'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Cooperante no hay camino...</title><content type='html'>¡Buenas chavalucos!&lt;br /&gt;&lt;br /&gt;Esta entrada es solo pa informar de que me viajo este mes de Octubre a realizar un proyecto de cooperación para el desarrollo en la región de Loreto, Perú, provincia del Alto Amazonas .Mi misión allí será junto con otros/as ingenieros/as realizar el mantenimiento y puesta a punto de una red telemática que intercomunica los centros de salud de los pueblos de la selva amazónica de aquella región, a orillas del río Napo, uno de los principales afluentes del Amazonas.&lt;br /&gt;&lt;br /&gt;Con motivo de este proyecto y de otros tantos que se realizarán financiados con fondos de la Oficina de Cooperación para el Desarrollo de Universidad Carlos III de Madrid, hemos abierto un blog donde trataremos de informar del estado de cada proyecto así como de las vivencias que se nos vayan ofreciendo en el camino. El blog se llama "&lt;a href="http://cooperantesuc3m.blogspot.com/"&gt;Cooperante no hay camino...&lt;/a&gt;" y espero que a más de uno le sirva para animarse a poner al servicio del desarrollo humano sus conocimientos técnicos.&lt;br /&gt;&lt;br /&gt;Durante ese periodo no podré poner entradas en este blog, pero prometo volver con ánimos para seguir colaborando con este blog tanto como me sea posible, aunque con Manolo ya tenéis información interesante para dar y regalar.&lt;br /&gt;&lt;br /&gt;Por el momento, me despido temporalmente de vosotros y espero que os parezca interesante la información que podáis leer sobre los proyectos de cooperación al desarrollo. ¡¡Hasta pronto!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-5727460260108582813?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/5727460260108582813/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=5727460260108582813' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5727460260108582813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5727460260108582813'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/09/cooperante-no-hay-camino.html' title='Cooperante no hay camino...'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7067848347665369638</id><published>2007-08-15T12:30:00.000Z</published><updated>2007-08-15T12:42:56.305Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='juerga'/><category scheme='http://www.blogger.com/atom/ns#' term='desfase'/><category scheme='http://www.blogger.com/atom/ns#' term='casamiento'/><category scheme='http://www.blogger.com/atom/ns#' term='boda'/><category scheme='http://www.blogger.com/atom/ns#' term='efeméride'/><category scheme='http://www.blogger.com/atom/ns#' term='alegría'/><title type='text'>YA SAN CASAOOOO, YA SAN CASAAAOOOO...</title><content type='html'>Pos eso, que Marivi y Manolo, socios de N-Idea Soluciones y colaboradores de este blog ya han hecho su roce oficial y se casaron el sábado pasao. Dentro de poco editaré esta entrada con alguna foto ilustrativa de la efeméride.&lt;br /&gt;&lt;br /&gt;   La fiesta insuperable, la novia guapísima y el novio mu elegante, la comida insuperable (por lo menos la mía), y hasta las mil y pico de la madrugá bebiendo, cantando, bailando y gritando "¡¡Vivan los novios!!" y demás alaridos propios del casamiento. Especialmente gracioso era el gesto de Manolo cada vez que gritaban "¡Viva el novio!" que se rodeaba y hacía el gesto de la "v" con los dedos a tol mundo.&lt;br /&gt;&lt;br /&gt;   Pos eso, que pa bodas la de Marivi y Manolo. De lo único que nos quedamos con ganas es de haber escuchao cantar más a la madre de Marivi, que ya tendrá ocasión de deleitarnos más si cabe en alguna otra ocasión.&lt;br /&gt;&lt;br /&gt;   Por mi parte, me levanté al día siguiente con un pestazo a bizcocho de chocolate que algún desalmao me restregó por la cara y que esperaré a la siguiente boda familiar pa devolvérsela ;).&lt;br /&gt;&lt;br /&gt;   Y ná más, ¡¡¡¡VIVAN LOS NOVIOS!!!! ...y a ver si montáis más fiestones como ese que estaremos esperándolos con muchas ganas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7067848347665369638?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7067848347665369638/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7067848347665369638' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7067848347665369638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7067848347665369638'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/08/ya-san-casaoooo-ya-san-casaaaoooo.html' title='YA SAN CASAOOOO, YA SAN CASAAAOOOO...'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7580092611425294892</id><published>2007-07-12T17:11:00.001Z</published><updated>2007-07-17T09:53:43.986Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Frameworks para RIAs</title><content type='html'>En esta cuarta entrega del desarrollo basado en Ajax, nos vamos a centrar en los diferentes frameworks existentes que nos pueden ayudar en nuestros desarrollos. Si no os habéis leído los posts anteriores, os recomiendo que os los leáis para entender mejor este:&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/06/qu-es-eso-del-ajax.html"&gt;¿Qué es eso del AJAX?&lt;/a&gt;: Introducción a ajax, a su funcionamiento y al objeto XMLHttpRequest.&lt;/li&gt;&lt;li&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-campeones-o-qu-es-eso-del.html"&gt;AJAX para CAMPEONES o ¿Qué es eso del AJAX? (Segunda Parte)&lt;/a&gt;: en este segundo post, nos adentramos un poco más en la implementación práctica a través de ejemplos de las llamadas asíncronas.&lt;/li&gt;&lt;li&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-supercampeones-o-sabremos.html"&gt;AJAX PARA SUPERCA&lt;/a&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-supercampeones-o-sabremos.html"&gt;MPEONES o ¿Sabremos alguna vez qué es AJAX? (III):&lt;/a&gt; en la tercera entrega vimos cómo hacer múltiples llamadas de forma simultánea y cómo enlazar múltiples llamadas secuenciales.&lt;/li&gt;&lt;/ul&gt;En este post vamos a ver diferentes alternativas de las que disponemos para agilizar nuestra tarea (otra gente se ha pegado con el teclado por nosotros). Vamos a ver, aunque existen muchísimos más, los siguientes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.yahoo.com/yui/"&gt;YUI&lt;/a&gt;: Yahoo User Interface, framework de Yahoo (que listo soy) para aplicaciones ricas de internet (RIA: Rich Internet Application). Muy completo y con un montón de ejemplos y documentación.&lt;/li&gt;&lt;li&gt;&lt;a href="http://dojotoolkit.org/"&gt;Dojo:&lt;/a&gt; Framework de la Dojo Foundation. Es también muy completo, quizás un poco más sencillo de utilizar que el de Yahoo y menos pesado para el explorador, aunque con menos documentación.&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/webtoolkit/"&gt;GWT:&lt;/a&gt; Google Web Toolkit. Es la implementación que da Google para Ajax sobre Java. En realidad, la filosofía de GWT es la de programar en Java y él interpreta el código Java para generar las páginas con los controles AJAX.&lt;/li&gt;&lt;li&gt;&lt;a href="http://ajax.asp.net/"&gt;AJAX ASP.NET&lt;/a&gt;: La implementación para asp.net de AJAX. Incluye, aparte del core de librerías de comunicación una librería de controles llamada &lt;a href="http://www.codeplex.com/AtlasControlToolkit"&gt;Atlas Control Toolkit&lt;/a&gt;. Se puede utilizar aunque no se utilice asp.net.&lt;/li&gt;&lt;/ul&gt;Todas estas librerías son de libre distribución. Por supuesto, existen muchas librerías de pago con controles flipantes que casi te programan la aplicación solas, pero los currelas de a pié, nos conformaremos con éstas (de hecho son muy buenas todas). Personalmente, la que más uso (todos los días) es la de ASP.NET, que hace cosas muy chulas. Tened en cuenta que en lo que más dan estos frameworks son controles para hacer nuestras aplicaciones más interactivas. Pero, vamos al tajo:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:130%;" &gt;Yahoo User Interface:&lt;/span&gt;&lt;br /&gt;Esta fue la primera librería que utilicé en mis pruebas. Tiene varias cosas muy buenas a tener en cuenta:&lt;ul&gt;&lt;li&gt;Una documentación muy buena con unas cheatsheets muy curradas.&lt;/li&gt;&lt;li&gt;Un mogollón de ejemplos con el código bien puesto.&lt;/li&gt;&lt;li&gt;Muchos controles&lt;/li&gt;&lt;li&gt;El respaldo de una gran empresa que soporta el proyecto (no te van a dejar tirado).&lt;/li&gt;&lt;/ul&gt;Cosas negativas que he visto y comprobado:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Puede llegar a ser bastante pesado para el cliente (las librerías javascript)&lt;/li&gt;&lt;li&gt;Es el framework más complejo con el que trabajar debido a que puedes hacer lo que quieras con él.&lt;/li&gt;&lt;/ul&gt;Este conjunto de librerías las puedes utilizar donde quieras porque son Javascript puro. De hecho, puedes mezclar diferentes librerías. ¿Os acordáis del ejemplo que puse en una de las entregas en el que se ponía el nombre y el servidor devolvía "Te devuelvo tu nombre: " y el nombre? Os acordéis o no, aquí tenéis ese mismo ejemplo pero implementado con YUI:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAjax/YUI/yui1.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/YUI/yui1.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;El código javascript utilizado se divide en dos partes: primero tenemos que importar los scripts de YUI que vayamos a utilizar (lo miramos en su web para saberlo) y después realizamos nuestros propios scritps:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/RpuJ5-7vu2I/AAAAAAAAAK0/Qf2xxdC_jBI/s1600-h/yui1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/RpuJ5-7vu2I/AAAAAAAAAK0/Qf2xxdC_jBI/s400/yui1.gif" alt="" id="BLOGGER_PHOTO_ID_5087811833284246370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Los scripts a importar dependerán de qué es lo que vamos a utilizar de la librería de controles de Yahoo. En la página web se indica para cada caso cuáles son necesarios. La parte de programación es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RpuKRe7vu3I/AAAAAAAAAK8/pfhJ84PfsTM/s1600-h/yui2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RpuKRe7vu3I/AAAAAAAAAK8/pfhJ84PfsTM/s400/yui2.gif" alt="" id="BLOGGER_PHOTO_ID_5087812237011172210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El meollo se encuentra en la línea &lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;YAHOO.util.Connect.AsyncRequest()&lt;/span&gt; que es la que crea el objeto XMLHttpRequest y realiza la llamada. Se le pasa el método, la url y una variable que contiene toda la información relativa a la función si va todo bien, la función si no va bien, los argumentos, etc. Es muy importante el orden, no podemos definir la variable callback antes de las funciones que manejarán las respuestas, ni podemos definir la variable callback después de la llamada al servidor.&lt;br /&gt;&lt;br /&gt;Utilizamos también uno de los controles de YUI, el container en su versión panel. La programación con YUI se puede realizar de dos maneras distintas, por marcación o por Javascript. Todos los controles se pueden definir directamente en Javascript (caso del ejemplo) o definir en HTML (Markup). Al definir por HTML, cuando se llama al método render, la librería busca determinadas clases css y las convierte en controles. El mismo panel que se define en el ejemplo con HTML sería:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RpuNRu7vu4I/AAAAAAAAALE/UFhnmSiHjBE/s1600-h/yui3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RpuNRu7vu4I/AAAAAAAAALE/UFhnmSiHjBE/s400/yui3.gif" alt="" id="BLOGGER_PHOTO_ID_5087815539841022850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La librería lee las clases y las renderiza en pantalla en forma de panel.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;"&gt;Framework Dojo:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Este es el siguiente framework con el que trabajé. Tiene otras ventajas e inconvenientes que el YUI. Los que encontré fueron los siguientes:&lt;br /&gt;&lt;br /&gt;Cosas buenas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Un montón de controles&lt;/li&gt;&lt;li&gt;Definición en la programación más intuitiva que la de YUI.&lt;/li&gt;&lt;li&gt;Menos importaciones a nuestras páginas&lt;/li&gt;&lt;/ul&gt;Cosas malas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;La documentación es mucho peor.&lt;/li&gt;&lt;li&gt;Existen menos ejemplos en la utilización de los diferentes controles.&lt;/li&gt;&lt;/ul&gt;Veamos un ejemplo. Os he puesto el mismo ejemplo que con YUI pero programado con Dojo. Lo podéis ver en:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAjax/Dojo/dojo1.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/Dojo/dojo1.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;El estilo de programación varía ligeramente entre ambos frameworks. En ambos disponemos de una parte de inicialización de dependencias que en el caso de YUI es mediante la incorporación de scripts y mediante Dojo se realiza más al estilo Java o C#:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RpyHAe7vu5I/AAAAAAAAALM/sQ7bz0soR_g/s1600-h/dojo1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RpyHAe7vu5I/AAAAAAAAALM/sQ7bz0soR_g/s400/dojo1.gif" alt="" id="BLOGGER_PHOTO_ID_5088090121395223442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo primero es importar la librería base dojo.js y después utilizamos la sentencia  para importar aquellas partes que vayamos a utilizar. Podemos utilizar una sintaxis del tipo &lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;dojo.require() dojo.require("dojo.widget.*");&lt;/span&gt;&lt;span style="color: rgb(255, 153, 0);"&gt; &lt;/span&gt;para importar todos los widgets. En este caso, como sólo vamos a utilizar el tipo Dialog pues lo importamos. La sentencia &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;djConfig = {isDebug:true};&lt;/span&gt; nos permite sacar mensajes de debug o de error en la librería por pantalla.&lt;br /&gt;&lt;br /&gt;Dojo se diferencia de YUI en que al definir los elementos HTML, introducimos un nuevo parámetro llamado &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;dojotype&lt;/span&gt; en el que le indicamos qué tipo de elemento dojo va a ser. De esta forma al inicializar el elemento en Javascript, la mayoría de la definición se encuentra en el elemento HTML. Vayamos por pasos: paso 1, el código HTML:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RpyJHe7vu6I/AAAAAAAAALU/xWAcZINzY98/s1600-h/dojo2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RpyJHe7vu6I/AAAAAAAAALU/xWAcZINzY98/s400/dojo2.gif" alt="" id="BLOGGER_PHOTO_ID_5088092440677563298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En el código definimos tres divs a los que les decimos que son dojotype="dialog". De esta forma, Dojo sabe que tiene que renderizarlos como diálogos. Además les definimos una serie de características propias de Dojo (las subrayadas en rojo): &lt;span style="color: rgb(51, 153, 153); font-weight: bold;"&gt;bgcolor&lt;/span&gt;&lt;span style="color: rgb(51, 153, 153);"&gt;(&lt;/span&gt;color de fondo de la pantalla no del div), &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;bgOpacity&lt;/span&gt;&lt;span style="color: rgb(51, 153, 153);"&gt;(&lt;/span&gt;opacidad del fondo de la pantalla), &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;toogle &lt;/span&gt;(forma en la que aparece o desaparece la pantalla) y &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;toogleDuration &lt;/span&gt;(duración del efecto de aparecer y desaparecer).&lt;br /&gt;&lt;br /&gt;El resto del código es html normal. Veamos cómo se definen los diálogos y las funciones (ved que llamo a dos funciones Javascript CargarNombre() y Empezar()).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RpyK2O7vu7I/AAAAAAAAALc/JoO2fV0jDMI/s1600-h/dojo3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RpyK2O7vu7I/AAAAAAAAALc/JoO2fV0jDMI/s400/dojo3.gif" alt="" id="BLOGGER_PHOTO_ID_5088094343348075442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;He dividido el Javascript en trozos. En la primera parte tenemos las definiciones de las variables que vamos a utilizar después, los tres diálogos, y las dos funciones manejadoras de los eventos de respuesta correcta y respuesta incorrecta, hasta aquí todo igual que antes. Tenemos también la función init, que se ejecuta al cargar la página que define el primer diálogo que aparece en pantalla. La definición es muy simple, solamente utilizamos la sentencia &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;dojo.widget.byId()&lt;/span&gt; y le pasamos el id del div que va a ser el diálogo (ese div tiene que tener el dojotype="dialog"). Le definimos el botón que va a ocultar el diálogo con la sentencia &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;setCloseControl()&lt;/span&gt;. Ved que podemos utilizar con los diálogos las sentencias &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;show()&lt;/span&gt; y &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;hide()&lt;/span&gt; para mostrarlos u ocultarlos desde cualquier parte del código. ¿Y las llamadas a servidor cómo se hacen? Pues veamos el resto del código:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/RpyMXu7vu8I/AAAAAAAAALk/dcUHUBeBmjs/s1600-h/dojo4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/RpyMXu7vu8I/AAAAAAAAALk/dcUHUBeBmjs/s400/dojo4.gif" alt="" id="BLOGGER_PHOTO_ID_5088096018385320898" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Tenemos la función &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;CargarNombre()&lt;/span&gt; que muestra el diálogo de espera y llama al servidor. Con Dojo, las llamadas se realizan utilizando el método dojo.io.bind al que le pasamos parámetros. Los más comunes y necesarios (algunos) son: &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;url &lt;/span&gt;(dirección a la que llamar), &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;load &lt;/span&gt;(método que controlará la respuesta correcta del servidor), &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;error &lt;/span&gt;(método que manejará la respuesta de error del servidor), &lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;mimetype &lt;/span&gt;(mimetype de los datos de la llamada).&lt;br /&gt;&lt;br /&gt;Dojo también permite realizar llamadas cross-domain mediante el método bind(), pero hay que importar el espacio dojo.require("dojo.io.XhrIframeProxy"), proque la llamada se realiza mediante un iFrame Proxy. Esto está aún en pruebas así que os aconsejo que vayáis a la documentación y os lo leáis.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;Conclusión (hasta la próxima):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Como se me está haciendo demasiado largo el post, dejaremos los dos frameworks restantes para el siguiente. Sólo comentaros mi experiencia con ambos: personalmente prefiero el framework de Dojo que es bastante más intuitivo de utilizar, aunque YUI tenga más documentación (es realmente buena), cuando empiezas a trabajar con Dojo y te empiezas a enterar de cómo funciona, es más liviano. De todas formas, al ser frameworks completamente independientes de plataformas, siempre podéis conjugarlos y utilizar aquellas partes que más os gusten de uno y de otro.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 153, 153);"&gt;Proximamente: GWT y ASP.NET AJAX&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7580092611425294892?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7580092611425294892/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7580092611425294892' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7580092611425294892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7580092611425294892'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/frameworks-para-rias.html' title='Frameworks para RIAs'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_uUP4eiIAPJ8/RpuJ5-7vu2I/AAAAAAAAAK0/Qf2xxdC_jBI/s72-c/yui1.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-5075218823318895298</id><published>2007-07-11T08:18:00.000Z</published><updated>2007-07-11T08:42:23.342Z</updated><title type='text'>Noticiones Varios</title><content type='html'>&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;Actualización:&lt;br /&gt;Ya he arreglado el bug del mapa, así que podéis disfrutar de él todo lo que queráis. ¿Qué os parece?&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Bueno chavales, hemos cambiado &lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;nuestra página web&lt;/span&gt;, dándole un nuevo aspecto. La podéis visitar en &lt;a href="http://www.nidea-soluciones.com/"&gt;http://www.nidea-soluciones.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Aunque todavía tenemos que darle un último retoque, os recomiendo visitar la parte de contacto y abrid el mapa. Nos hemos integrado con el API de Google MAPS y ha quedado resultón. He detectado un pequeño bug que corregiré en breve.&lt;br /&gt;&lt;br /&gt;Por otro lado, &lt;span style="color: rgb(204, 153, 51); font-weight: bold;"&gt;SUPER NOTICIA&lt;/span&gt;, &lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:130%;" &gt;Producciones Porunbujero&lt;/span&gt; ha empezado su actividad como estudio de grabación y productora de vídeos. Estamos trabajando en su página web, podéis visitarla (sólamente está la portada) para obtener los datos de contacto. Su dirección es: &lt;a href="http://www.porunbujero.com/"&gt;http://www.porunbujero.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RpST1705drI/AAAAAAAAAKs/b9dUohtoddc/s1600-h/Logo_Bujero.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RpST1705drI/AAAAAAAAAKs/b9dUohtoddc/s400/Logo_Bujero.jpg" alt="" id="BLOGGER_PHOTO_ID_5085852434010044082" border="0" /&gt;&lt;/a&gt;Os doy sus datos de todas maneras:&lt;br /&gt;&lt;br /&gt;Producciones Porunbujero&lt;br /&gt;Tejuela 25, Alcalá la Real&lt;br /&gt;605978242&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-5075218823318895298?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/5075218823318895298/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=5075218823318895298' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5075218823318895298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/5075218823318895298'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/noticiones-varios.html' title='Noticiones Varios'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_uUP4eiIAPJ8/RpST1705drI/AAAAAAAAAKs/b9dUohtoddc/s72-c/Logo_Bujero.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7220888449383921997</id><published>2007-07-08T22:19:00.000Z</published><updated>2007-07-09T00:42:38.236Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='J2EE'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Creación de un EJB(I): Session Bean</title><content type='html'>Bueno, después de este pequeño traspiés con la nueva versión de J2EE, voy a ir contándoos lo que voy haciendo para crear un bean de sesión desde donde lo dejé. Recordemos que en el &lt;a href="http://nidea-soluciones.blogspot.com/2007/06/j2ee-programacin-de-servidores-de.html"&gt;primer post&lt;/a&gt; hablamos sobre la tecnología J2EE y en el &lt;a href="http://nidea-soluciones.blogspot.com/2007/07/instalacin-del-servidor-de-aplicaciones.html"&gt;segundo post&lt;/a&gt; habíamos instalao nuestro servidor de aplicaciones de Sun. Por lo que me comentó Manolo, existe también otro servidor de aplicaciones llamado JBOSS que parece ser que es más eficiente, pero como yo ya había trabajao con una versión previa de éste, os voy a contar cómo se hace ésto. También he visto por ahí que hay un proyecto open source llamado GlashFish que creo que también es un servidor de aplicaciones y tiene buena pinta pero eso es arena de otro costal que ya urgaremos cuando proceda. Yo voy a lo mío.&lt;br /&gt;&lt;br /&gt;Después de instalar el servidor de aplicaciones, en la nueva versión, necesitamos para desplegar nuestras aplicaciones un pack para Netbeans o un plugin para eclipse que se ofrecen junto con el servidor de aplicaciones en la página de Sun. Ésas eran las herramientas que se descargaban si en vez de pulsar en &lt;span style="font-style: italic;"&gt;Download with JDK&lt;/span&gt; pulsábamos en &lt;span style="font-style: italic;"&gt;Download with Tools&lt;/span&gt;. Como por entonces no tenía ni idea de que ya no existía la herramienta de despliegue &lt;span style="font-style: italic;"&gt;deploytool&lt;/span&gt;, pues yo ya tengo mi servidor de aplicaciones instalao en mi máquina. No todo está perdido. Yo he escogido hacerlo con NetBeans como reto personal porque ya conocía Eclipse y tenía ganas de ver qué tal era NetBeans, pero vosotros podéis hacerlo con lo que elijáis.&lt;br /&gt;&lt;br /&gt;Bien, para empezar nos vamos a la &lt;a href="http://java.sun.com/javaee/downloads/index.jsp"&gt;página de descarga de Sun&lt;/a&gt; y pinchamos en un link que hay a la derecha en un div azul titulado Related Resources y que se llama &lt;a href="http://www.netbeans.org/products/index.html"&gt;NetBeans&lt;/a&gt;. Ahí podemos descargarnos tanto el propio IDE NetBeans como el Enterprise Pack. Descargad agusto. Luego la instalación es bastante simple. Hacemos un &lt;span style="font-style: italic;"&gt;chmod +x fichero_binario&lt;/span&gt; y luego un &lt;span style="font-style: italic;"&gt;./fichero_binario&lt;/span&gt;. Con ésto se nos abre un instalador gráfico bastante intuitivo al que la máxima información que tendremos que aportarle será el sitio donde queremos que lo instale cuando se trate del IDE o del sitio donde hemos instalao el IDE cuando se trate del Enterprise Pack. Habrá un momento de la instalación que nos preguntará si queremos instalar un servidor de aplicaciones o si queremos usar una instalación preexistente. Obviamente aquí usaremos el servidor que habíamos instalao en el post anterior y para ello tendremos que darle el nombre de usuario y la contraseña de administrador que nos creamos en su momento.&lt;br /&gt;&lt;br /&gt;Aparte de ésto, lo demás no os creará problemas. Y bien, ahora tenemos nuestro servidor de aplicaciones perfectamente sincronizao con nuestro IDE NetBeans que hemos instalao para el desarrollo de nuestros beans y sólo nos queda desarrollar las aplicaciones.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0); font-weight: bold;font-size:180%;" &gt;Creación de un Bean de Sesión - El meollo.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Vamos a crearnos un Bean de Sesión que a partir de un día, mes y año de nacimiento calcule la edad que debe tener la persona. Además posteriormente y para ver la funcionalidad de ésto, nos vamos a crear una página JSP que haga uso de este Bean para recoger la información introducida por un usuario, mandársela al bean, recoger el resultado y mostrarlo por pantalla. Al lío pues.&lt;br /&gt;&lt;br /&gt;Arrancamos NetBeans si no lo hemos hecho ya y pinchamos en Archivo -&gt; Nuevo Proyecto -&gt; Nueva Aplicación Empresarial. Rellenamos los campos necesarios. En nuestro caso le vamos a poner de nombre CalculadorEdad. Ponemos la carpeta donde queremos que se guarde y seleccionamos la versión de J2EE que queremos usar. En este primer post vamos a usar J2EE 1.4 que es la versión que yo había trabajado, pero a ver si más adelante os puedo escribir cómo hacerlo con J2EE 5 para que veáis la diferencia. Aseguráos antes de darle a "Terminar" de que marcáis las casillas de "Crear módulo EJB" y "Crear módulo de aplicación Web" y dejad sin marcar la de "Crear módulo de aplicación Web" de abajo que se refiere a un cliente de aplicación web que nosotros no necesitaremos, sólo los dos primeros. Debería quedar parecido a lo que sigue:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/Ro73g9-QpGI/AAAAAAAAACs/bEPAf6dtFJ8/s1600-h/configuracion2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/Ro73g9-QpGI/AAAAAAAAACs/bEPAf6dtFJ8/s320/configuracion2.png" alt="" id="BLOGGER_PHOTO_ID_5084273175111443554" border="0" /&gt;&lt;/a&gt;Pinchad en "Terminar".&lt;br /&gt;&lt;br /&gt;Ahora creamos el nuevo Session Bean. Para ello le damos al botón derecho en CalculadorEdad-ejb -&gt; Nuevo -&gt; Bean de sesión.&lt;br /&gt;Introducimos el nombre que será CalculadorEdad, ponemos el nombre de un paquete, que será por ejemplo "calculadoredad". Marcamos "sin estado" puesto que vamos a hacer un Stateless Session Bean, ponemos el tick en las dos interfaces, remota y local y pinchamos en Terminar. En realidad podríamos valernos sólo con la Remota, ya que la local es para optimizar accesos desde local pero vamos a ponerlo todo y así vemos todas las interfaces en pleno rendimiento. El resultado será que nos creará automáticamente las clases que necesitamos e implementará él sólo el código aburrido de los métodos de ciclo de vida y demás asuntos escabrosos. A nosotros nos tocará entonces implementar los métodos de negocio que son los específicos de nuestro bean. La intención es crear una aplicación que introduciendo una fecha de nacimiento calcule los años que tiene la persona dada. Así pues, nuestro método de negocio lo llamaremos edad y recibirá como parámetros 3 int representando el día, mes y año de nacimiento. Además le diremos que lanza una excepción que llamaremos PeroQueInventoEsEsteException y que extiende de Exception para indicar cuando alguien ha introducido una fecha no válida (ya se que aún no la hemos creado, lo haremos a continuación).&lt;br /&gt;&lt;br /&gt;Si le damos al botón derecho en la clase CalculadorEdadBean , y seleccionamos métodos EJB -&gt; Agregar método Business podremos añadir nuestro método de negocio que os describía arriba y el código se implementa sólo. Jurch, estos IDEs...dentro de poco no habrá que saber programar para programar :).&lt;br /&gt;&lt;br /&gt;Justo después de haber puesto todo lo que arriba decíamos vamos a crearnos nuestra excepción especial. Para eso nos vamos dentro de CalculadorEdad-ejb al apartado de "Paquetes de orígen". Le damos al botón derecho encima y decimos Nuevo -&gt; Clase java. Como nombre le damos PeroQueInventoEsEsteException y le decimos que la cree. A continuación la abrimos haciendo doble click en ella y añadimos a su declaración de clase el código "extends Exception" para que tenga las propiedades de una excepción normal y corriente. Luego en el constructor por defecto metemos como código "super();" y nos creamos un constructor con un String como parámetro que tenga por código "super(motivo);" siendo motivo el nombre del String del parámetro. Ya tenemos nuestra excepción.&lt;br /&gt;&lt;br /&gt;Ahora vamos a implementar el código de nuestro método de negocio. Para ello nos vamos a la clase CalculadorEdadBean que es quien tiene que implementar el código de nuestro bean y picamos código. Mi implementación to perrillera del método que calcula la edad es la que os pongo aquí.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;public int edad(int dia, int mes, int anho) throws PeroQueInventoEsEsteException{&lt;br /&gt;//Obtenemos un objeto java.util.Date con la fecha actual y un objeto java.sql.Date con la fecha que ha introducido el usuario&lt;br /&gt;java.sql.Date fecha = java.sql.Date.valueOf(new Integer(anho).toString()+"-"+new Integer(mes).toString()+"-"+new Integer(dia).toString());&lt;br /&gt;hoy = new Date();&lt;br /&gt;//Para compararlos obtengo el número de milisegundos desde "The Epoch"&lt;br /&gt;long nacimiento = fecha.getTime();&lt;br /&gt;long actual = hoy.getTime();&lt;br /&gt;&lt;br /&gt;//Si se ha introducido una fecha futura...&lt;br /&gt;if(nacimiento&gt;actual){&lt;br /&gt;throw new PeroQueInventoEsEsteException("¿Tu tas creído que somos unos pardillos o qué? ¿usease que aún no has nacío no?");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Calculamos el tiempo en milisegundos que la persona lleva viviendo y hayamos su edad averiguando cuántos años son esos milisegundos. Hay un error obvio debido a los años bisiestos pero no lo contemplaremos aquí.&lt;br /&gt;long tiempoDeVida = actual-nacimiento;&lt;br /&gt;int edad = (int)(((tiempoDeVida/1000)/3600)/24)/365;&lt;br /&gt;&lt;br /&gt;return edad;&lt;br /&gt;}&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;Hago uso de java.util.Date (que está importada en el inicio de la clase con un simple "import java.util.Date") y de java.sql.Date por la facilidad de uno para crear objetos Date a partir de Strings y la facilidad del otro para crear objetos Date representando la fecha actual. Como ambos tienen un método getTime() que devuelve el número de milisegundos desde "The Epoch" que es como se conoce a las 00:00h del 1 de enero de 1970, mediante una simple resta puedo tener los milisegundos de vida de la persona que ha introducido su fecha de nacimiento. Paso los milisegundos a años y voilà, ya tenemos su edad. Está claro que no estoy contemplando los bisiestos y ésto sería un problema, pero como la propia implementación es bastante perrillera no me voy a centrar en que el código sea bonito o que cumpla bien con su cometido, sino en que veáis una implementación de un EJB. Además la aproximación es bastante cercana, y sólo fallará en días próximos a nuestro cumpleaños así que lo podemos considerar aceptable para un ejemplo :). De toas formas sí, ya se que es un código un tanto perrillero, pero weno, qué le vamos a hacer.&lt;br /&gt;&lt;br /&gt;Lo único que nos queda por hacer con el Bean es darle un nombre de referencia en el servidor para que pueda ser encontrado por nuestra página web (que crearemos a continuación) cuando vaya a buscarlo. Ésto es fácil. Nos vamos al menú de la izquierda, donde está nuestro CalculadorEdad-ejb. Desplegamos el submenú "Archivos de configuración" y hacemos doble click encima de "sun-ejb-jar.xml". Ese fichero es en realidad un xml, pero nuestro querido IDE NetBeans nos lo mostrará como cajitas y menús tó wapos (si es que vivimos en una puta metáfora con las interfaces gráficas ;) ). Veréis que debajo de "Configuración Sun" tenéis un submenú llamado CalculadorEdadBean, pues pinchad en él, y veréis algo como ésto:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/Ro701N-QpFI/AAAAAAAAACk/cPCR13GfLTA/s1600-h/configuracion1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/Ro701N-QpFI/AAAAAAAAACk/cPCR13GfLTA/s320/configuracion1.png" alt="" id="BLOGGER_PHOTO_ID_5084270224468911186" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Rellenadlo como véis en la imágen, poniendo "ejb/CalculadorEdadBean" en el campo de "Nombre JNDI". Ya tenemos nuestro bean programado y reconocido por el servidor para que pueda ser llamado por otras aplicaciones, servlets, beans o JSPs.&lt;br /&gt;&lt;br /&gt;Ahora nos vamos a crear una página JSP. En realidad esta página ya está creada. Se creó automáticamente cuando marcamos la casilla de "Crear módulo de aplicación Web" cuando creamos el proyecto. Para verla, id en el menú de la izquierda a "CalculadorEdad-war" y desplegad su submenú. De ahí nos vamos a páginas web y veréis que hay una que se llama "index.jsp". Ésta es la que nuestro servidor de aplicaciones mostrará cuando ejecutemos la aplicación y entremos en &lt;span style="font-style: italic;"&gt;localhost:8080/CalculadorEdad-war&lt;/span&gt;. Pinchad dos veces sobre ella y se os abrirá a la derecha. Ahora la vamos a editar. Os voy a enseñar el código en dos trozos pa ir explicándooslo poco a poco. Primer cacho:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8BNN-QpHI/AAAAAAAAAC0/RSK7H3HnAm4/s1600-h/jsp1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8BNN-QpHI/AAAAAAAAAC0/RSK7H3HnAm4/s320/jsp1.png" alt="" id="BLOGGER_PHOTO_ID_5084283830925304946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;De lo que veis, llamaros la atención sobre unas pocas cosas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No os olvidéis de importar las clases necesarias para el funcionamiento de vuestra página JSP, además de las clases de las interfaces del Bean que váis a usar.&lt;/li&gt;&lt;li&gt;Cread un contexto inicial como se ve en el código.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fijáos en la forma de obtener una referencia a nuestro Bean. Primero se obtiene una referencia al interfaz de inicio o interfaz Home de nuestro Bean sobre la que llamaremos a su método create(). Lo hacemos con el método lookup(String) sobre nuestro contexto inicial y le preguntaremos por "java:comp/env/" + el nombre que le dimos a la referencia del EJB. ¿Os acordáis? Lo que sí recordaréis seguro es que en los Session Beans el bean nace y muere con el cliente, así que aquí no tendría mucho sentido obtener la referencia de otra forma. La creamos cada vez y punto.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Ahora pasamos al segundo cacho:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8CCN-QpII/AAAAAAAAAC8/tg7W3Fd3D-w/s1600-h/jsp2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8CCN-QpII/AAAAAAAAAC8/tg7W3Fd3D-w/s320/jsp2.png" alt="" id="BLOGGER_PHOTO_ID_5084284741458371714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Aquí está la chicha de nuestra página. Quitando el código que es meramente HTML, lo más importante quizás sea lo que está a partir de la línea 47. Tened en cuenta que cuando llamemos a nuestra página JSP lo podremos hacer pasándole parámetros en la propia URL del tipo dia=4&amp;mes=5&amp;amp;anho=1984. Ésta es la forma de funcionar de una petición "GET". Para recuperar esos parámetros en nuestro JSP tendremos siempre el objeto request siempre inicializado y que indica la petición, y si llamamos a su método getParameter("parametro"), éste nos podrá devolver o el valor del parámetro, o bien null, y debemos contemplar esa posibilidad. También contemplamos la posibilidad de que el usuario pinche sobre el botón sin haber introducido nada (se hace en las comprobaciones noseque.length()&gt;0) por lo que se estará enviando una cadena vacía. Una vez capturados los parámetros con los que se ha llamado a nuestra página JSP mediante nuestro formulario que generaba peticiones "GET" sobre la propia página, los transformamos en el tipo de dato que necesitábamos, para ello apoyándonos en la clase java.lang.Integer y llamamos al método de negocio edad(int,int,int) que nos habíamos creado usando la referencia que obtuvimos en el primer cacho de código. Al realizar la llamada tenemos que encapsularla por un try-catch que recoja las excepciones que se puedan producir, que en nuestro caso será la excepción especial cachonda que nos habíamos creao. Y finalmente, si la excepción no se ha producido sólo tenemos que mostrar el mensaje con el resultado de la llamada a nuestro bean. ¿A que no es complicao?&lt;br /&gt;&lt;br /&gt;Por último, vamos a crear una referencia al EJB en nuestro módulo de aplicación web. Cosa sencillica. Nos vamos al menú de la izquierda de NetBeans. Desplegamos el menú de "CalculadorEdad-war" y dentro de él el submenú de "Archivos de configuración". Hacemos doble click sobre web.xml. Aquí pasa como antes, que pese a que es un fichero xml, nuestro IDE nos lo muestra de forma bonica (si queréis ver su forma real podéis pinchar en el botón "XML" que os lo enseñará perfectamente). Ya trastearéis un poquillo por este fichero para descubrir que se pueden configurar muchísimas cosas, como por ejemplo el tiempo que dura una sesión o temas de seguridad y demás, pero lo que a nosotros nos importa lo conseguimos pinchando en el botón de "Referencias". Ahí desplegaremos "Referencias EJB" y pincharemos sobre "Agregar". Ahí se os mostrará algo como:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8EBd-QpJI/AAAAAAAAADE/RXKlnBLdulA/s1600-h/referenciaEJB.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8EBd-QpJI/AAAAAAAAADE/RXKlnBLdulA/s320/referenciaEJB.png" alt="" id="BLOGGER_PHOTO_ID_5084286927596725394" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Rellenadlo como ahí pongo. Aquí fijáos que en el nombre de la referencia tiene que haber una coherencia con el nombre que configuramos antes en el servidor al EJB. Luego, dado que hemos metido las distintas clases de nuestro EJB en un paquete llamado calculadoredad, fijáos en que al indicar las interfaces de inicio y remota hemos puesto delante calculadoredad.*, es importante. Una vez que hayáis hecho ésto, pinchamos en guardar y tocad la madera más cercana porque se supone que ya lo tenemos todo listo para desplegar nuestra aplicación. Lo que sigue es fácil. Le damos al botón derecho encima de "CalculadorEdad", que es la raíz de nuestro menú de la izquierda y seleccionamos "Ejecutar Proyecto". Nos saldrán un chorro de letras por abajo, os pedirá el nombre de usuario y contraseña de administrador y parecerá que nuestra máquina esté intentando calcular todos los números de pi, pero cuando lleve un rato leeréis algo así como "GENERACIÓN CORRECTA" y sabréis que todo este tiempo habrá merecido la pena :). Que no os lleve a engaños, este mensaje aparece también cuando la mayoría de las cosas fallan. Depende del tipo de fallo que se produzca. Si las referencias las habéis puesto mal o el código no rula como debería de rular, el mensaje os aparecerá, pero cuando intentéis entrar en vuestra página lo que salga o cómo funcione la aplicación...eso ya será otro rollo.&lt;br /&gt;&lt;br /&gt;Para comprobar que la cosa rula abrimos un navegador y metemos la dirección&lt;br /&gt;http://localhost:8080/CalculadorEdad-war/&lt;br /&gt;Si todo ha ido medianamente bien debería de mostrársenos algo como ésto...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8HJd-QpKI/AAAAAAAAADM/lTBFsxiZ3ag/s1600-h/resultados1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8HJd-QpKI/AAAAAAAAADM/lTBFsxiZ3ag/s320/resultados1.png" alt="" id="BLOGGER_PHOTO_ID_5084290363570562210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Ahora introducimos un día de nacimiento, mes y año correctos, por ejemplo Día: 4, Mes: 5, Año: 1984, y pinchamos en "Submit". Nos debería salir algo como...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8H5N-QpLI/AAAAAAAAADU/zUPHAidvBnU/s1600-h/resultados2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/Ro8H5N-QpLI/AAAAAAAAADU/zUPHAidvBnU/s320/resultados2.png" alt="" id="BLOGGER_PHOTO_ID_5084291183909315762" border="0" /&gt;&lt;/a&gt;Es correcto. Pero, ¿qué pasa si introducimos una fecha en el futuro? ¿cómo manejará nuestra página aquella PeroQueInventoEsEsteException que nos inventamos? ¡Probémoslo! El resultado debería parecerse a éste...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8Ikd-QpMI/AAAAAAAAADc/5POBw6iXHJE/s1600-h/resultados3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/Ro8Ikd-QpMI/AAAAAAAAADc/5POBw6iXHJE/s320/resultados3.png" alt="" id="BLOGGER_PHOTO_ID_5084291926938657986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Wapo ¿verdad?. En realidad, seguramente no queráis hacer una aplicación de un servidor de aplicaciones que maneje una página que te calcula tu edad con un cierto márgen de error de días según bisiestos...es mu probable que no, pero hacer un calculador de edad es lo mismo que hacer cualquier otra cosa, sólo cambiad el código y número de los métodos de negocio y fenómeno. Se que es un poco tedioso, pero también hay que tener en cuenta que en este ejemplo nosotros hemos hecho todo el trabajo. En un servidor de aplicaciones real seguramente no tuviéramos que hacerlo. Ahí es donde entra el reparto de roles que contempla este tipo de programación. El desarrollador no tiene por qué ser el mismo que el desplegador, que a su vez no hace falta ni que conozca a quien montó el servidor de aplicaciones. Por eso os enseñé en el anterior post cómo arrancar y parar el servidor desde línea de comandos, pues puede que os toque símplemente hacer ésto y no desarrollar nada encima. Una vez montado el sistema, ya es sólo cuestión de hacer correr distintas aplicaciones sobre él y si somos listos al cliente le cambiaremos muy poco la interfaz para no hacerle la picha un lío, como al fin y al cabo lo que va por debajo no le importa, sólo tenemos que añadir métodos de negocio y añadir nuevas funcionalidades en nuestra interfaz que nunca cambia :). Todo ventajas. Inconveniente: ésto es java, así que ya se sabe, el procesador echando humo y la memoria derrochándose. Pero weno, dejemos eso para otro momento.&lt;br /&gt;&lt;br /&gt;El desarrollo de un EJB de sesión con estado es bastante similar al del sin estado que hemos desarrollado así que el siguiente post lo dedicaré a crear un EJB de entidad (con una bonita base de datos derby). Espero no haberos aburrido mucho y que ésto os pueda servir para introduciros en cómo hacer lo que ya sabéis que queréis hacer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7220888449383921997?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7220888449383921997/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7220888449383921997' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7220888449383921997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7220888449383921997'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/creacin-de-un-ejbi-session-bean.html' title='Creación de un EJB(I): Session Bean'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_Odz8IS0Tz3k/Ro73g9-QpGI/AAAAAAAAACs/bEPAf6dtFJ8/s72-c/configuracion2.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-8773525885765467781</id><published>2007-07-03T16:25:00.000Z</published><updated>2007-07-06T15:24:26.817Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>AJAX PARA SUPERCAMPEONES o ¿Sabremos alguna vez qué es AJAX? (III)</title><content type='html'>Hala, de vuelta con el tema Ajax (la verdad es que da mucho juego el tema...). En esta tercera entrega de esta serie nos vamos a centrar en los siguientes dos temas:&lt;br /&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Llamadas simultáneas: es decir, realizar múltiples llamadas a diferentes sitios a la vez.&lt;/li&gt;&lt;li&gt;Llamadas asíncronas secuenciales: este es un tema importante, saber &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;cómo hacer llamadas asíncronas de forma ordenada&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Si no os habéis leído los posts anteriores, os recomiendo que lo hagáis:&lt;br /&gt;&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/06/qu-es-eso-del-ajax.html"&gt;¿Qué es eso del AJAX?&lt;/a&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-campeones-o-qu-es-eso-del.html"&gt;AJAX para CAMPEONES o ¿Qué e&lt;/a&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-campeones-o-qu-es-eso-del.html"&gt;s eso de&lt;/a&gt;&lt;a href="http://nidea-soluciones.blogspot.com/2007/07/ajax-para-campeones-o-qu-es-eso-del.html"&gt;l AJAX? (Segunda Parte)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Como sé que ya te los has leído, Nacho, puedes seguir con el siguiente punto ;P. En este post, terminamos la serie de &lt;span style="color: rgb(0, 153, 0);"&gt;AJAX PARA CAMPEONES&lt;/span&gt; o &lt;span style="color: rgb(0, 153, 0);"&gt;AJAX A PELO&lt;/span&gt; o &lt;span style="color: rgb(0, 153, 0);"&gt;AJAX KAMIKAZE&lt;/span&gt;, es decir, &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;ajax para frikies&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-size:130%;" &gt;Llamadas simultáneas&lt;/span&gt;&lt;br /&gt;Una de los beneficios más importantes de trabajar con hebras de ejecución es que podemos crear tantas como nos permita el entorno (hardware, línea de comunicación, etc.) y el objeto XMLHttpRequest no es menos. Trabajando con AJAX podremos, por lo tanto, lanzar mútliples hilos de comunicación de forma simultánea que ejecutarán tareas distintas. Tendremos que tener cuidado de manejar correctamente las respuestas, de forma que sepamos siempre de quién es cada una.&lt;br /&gt;&lt;br /&gt;En el ejemplo que os pongo aquí, podéis realizar tres llamadas simultáneas para que se carguen en los divs inferiores la página web que hayáis puesto. No es que esté demasiado currado pero menos es nada.&lt;br /&gt;&lt;br /&gt;Ejemplo: &lt;a href="http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax5.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax5.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Existen ciertas peculiaridades para que este ejemplo funcione:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Se ha creado una nueva función &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;E&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;nviarPeticionConParametro&lt;/span&gt; que además de realizar la petición le pasa un parámetro a la función que maneja la respuesta (aparte del objeto XMLHttpRequest).&lt;/li&gt;&lt;li&gt;Se ha implementado un Proxy al que llama la página para que se puedan hacer llamadas &lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;asíncronas CRO&lt;/span&gt;&lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;SS-DOMAIN&lt;/span&gt;. Ésto lo explicaré otro día.&lt;/li&gt;&lt;/ul&gt;El código de la nueva función es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/RoqS5xn1ISI/AAAAAAAAAJ0/gQfwXuh3qps/s1600-h/Ajax11.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/RoqS5xn1ISI/AAAAAAAAAJ0/gQfwXuh3qps/s400/Ajax11.gif" alt="" id="BLOGGER_PHOTO_ID_5083036650711621922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Como veis, introducimos un nuevo argumento llamado "parametro" que se le pasará a la función callback. Con este parámetro podremos decirle a la función callback &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;qué objeto es el que ha realizado la llamada y ha respondido&lt;/span&gt;. Lo marco porque es muy importante ya que cada llamada tardará el tiempo que sea y devolverá el resultado en orden aleatorio. Tenemos que disponer de algún método que asocie la llamada con la respuesta.&lt;br /&gt;&lt;br /&gt;Para entenderlo mejor, veamos el código de la página y cómo se realiza la llamada:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RoqUGRn1ITI/AAAAAAAAAJ8/Ubqj1jnUhGU/s1600-h/Ajax12.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RoqUGRn1ITI/AAAAAAAAAJ8/Ubqj1jnUhGU/s400/Ajax12.gif" alt="" id="BLOGGER_PHOTO_ID_5083037964971614514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En este caso, tenemos la función CargaURL(posicion), donde en posición se le pasa un 1, un 2 o un 3, dependiendo de qué botón es el pulsado. En base a ese número, se leerá el input correspondiente y se mostrará el panel de espera asociado. Finalmente se llama a la función EnviaPeticionConParametro y se le pasa la posición como parámetro final.&lt;br /&gt;&lt;br /&gt;A la función que maneja la respuesta le llega el parámetro de la posición por lo que es capaz de poner la respuesta en el div correcto y oculta el div de espera correspondiente. De esta forma podemos tener &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;una sola función que gestiona todas las llamadas&lt;/span&gt; y &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;otra función que gestiona todas las respuestas&lt;/span&gt;. Si no lo hiciésemos así tendríamos que asociarle una función diferente a cada respuesta.&lt;br /&gt;&lt;br /&gt;Os pongo un dibujo que como sabéis me molan y en el post anterior no tuve oportunidad de poner ninguno:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/RoqYZhn1IUI/AAAAAAAAAKE/fOwnmBolHHU/s1600-h/Ajax13.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/RoqYZhn1IUI/AAAAAAAAAKE/fOwnmBolHHU/s400/Ajax13.gif" alt="" id="BLOGGER_PHOTO_ID_5083042693730607426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Las peticiones se envían al servidor, el cual las gestionará y tardará un tiempo x. Al ser asíncronas, &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;las peticiones se evaluarán de forma simultánea&lt;/span&gt; y a medida que las vaya resolviendo irá mandando la respuesta. El orden de evaluación y respuesta no es fijo por lo que el orden de llegada de las peticiones no tiene por qué tener relación con el de salida. Es muy típico equivocarse con este concepto y escribir lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 102, 255);"&gt;func&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(51, 102, 255);"&gt;tion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt; MiFuncionQueRealizaMuchasCosas()&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="color: rgb(0, 153, 0);"&gt;// Primera accion asíncrona&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;    &lt;span style="color: rgb(51, 51, 51);"&gt;ActualizaDatos&lt;/span&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="color: rgb(51, 102, 255);"&gt;&lt;span style="color: rgb(51, 51, 51);"&gt;MuestraDatosActualizados&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 0);"&gt;Error,&lt;/span&gt; al ser la función ActualizaDatos una llamada asíncrona a servidor, perderemos ese hilo de ejecución hasta que lo recoja el manejador de la respuesta. Por esto, la función MuestraDatosActualizados() no mostrará esos datos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-size:130%;" &gt;Llamadas asíncronas secuenciales&lt;/span&gt;&lt;br /&gt;Por fin, el último ejemplo, lo último del AJAX PARA CAMPEONES. Este ejemplo se lo dedico con mucho cariño a Nacho porque sé que es tela de friki del Linux y en especial de Kubuntu y Ubuntu. Espero que te guste.&lt;br /&gt;&lt;br /&gt;Como ya estaba harto de páginas html guarras con el texto a pelote decidí currarme un poquillo más este último ejemplo del post. En este ejemplo se realizan seis llamadas a servidor secuenciales, hasta que no se recibe la contestación de una no se realiza la siguiente. Podéis ver el ejemplo en la siguiente dirección (funciona mejor con Firefox porque el IE, a partir de la segunda vez, se pasa por el forro el delay que le tengo puesto en servidor):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax6.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax6.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Mola cantidad, eh? Por lo menos le damos un poco de aqué al tema. En fin, vamos al lío. ¿Cómo se hace esto? Aparte del tema gráfico (cada uno lo pone como más le gusta), la secuenciación de llamadas se realiza de la siguiente manera (os lo pongo en tres imágenes porque no me cabía en una):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/Rouvxr05dnI/AAAAAAAAAKM/I7hVQ-dudj4/s1600-h/Ajax14.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/Rouvxr05dnI/AAAAAAAAAKM/I7hVQ-dudj4/s400/Ajax14.gif" alt="" id="BLOGGER_PHOTO_ID_5083349872530781810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RouwCL05doI/AAAAAAAAAKU/Tn10bhZ12hw/s1600-h/Ajax15.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RouwCL05doI/AAAAAAAAAKU/Tn10bhZ12hw/s400/Ajax15.gif" alt="" id="BLOGGER_PHOTO_ID_5083350155998623362" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RouwU705dpI/AAAAAAAAAKc/qbwbJ0bb_WY/s1600-h/Ajax16.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RouwU705dpI/AAAAAAAAAKc/qbwbJ0bb_WY/s400/Ajax16.gif" alt="" id="BLOGGER_PHOTO_ID_5083350478121170578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo que hacemos es lo siguiente:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Cuando el usuario pulsa sobre el botón, mostramos el divProgreso y le ponemos la primera imagen grande y su texto. Llamamos a la url Codigos/PruebaAjax6.aspx para ir a servidor.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Cuando se recibe la respuesta, se pone la imagen en pequeño, se pone en grande la siguiente y la descripción de la acción y se realiza la llamada a la página con el parámetro del siguiente paso.&lt;/li&gt;&lt;li&gt;Así sucesivamente hasta que en la última llamada, invocamos a la página redireccion.html. Obtenemos su código html y lo metemos dentro del div wrapper que engloba a toda la página.&lt;/li&gt;&lt;/ol&gt;Viéndolo en un dibujillo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/Rou4yr05dqI/AAAAAAAAAKk/JKMUlZjFzYU/s1600-h/Ajax17.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/Rou4yr05dqI/AAAAAAAAAKk/JKMUlZjFzYU/s400/Ajax17.gif" alt="" id="BLOGGER_PHOTO_ID_5083359785315301026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Es en las funciones callback donde realizamos la siguiente llamada.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;El finaaaal deeeel veraaanooooo, llegoooo.....&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Como todo, en algún momento hemos de llegar al final e igual que el verano todo acaba. Creo que con esta serie de ejemplos cubrimos la base de la comunicación asíncrona y del &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;AJAX PARA CAMPEONES&lt;/span&gt;. Como os habréis percatado, el manejo del Javascript es fundamental (por Dios, nooooo), aunque, como veremos en posts posteriores, existen frameworks que nos ayudarán en nuestro cometido (un poco). Es importante que os deis cuenta que es indiferente el lenguaje de programación que utilicéis (yo lo he hecho todo en html plano), simplemente debe permitir hacer llamadas a funciones Javascript.&lt;br /&gt;&lt;br /&gt;En próximos capítulos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Frameworks Ajax&lt;/li&gt;&lt;li&gt;Llamadas Cross-Domain&lt;/li&gt;&lt;/ul&gt;Se me está ocurriendo hacer también algún post con el tema de los &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;Mash-Ups&lt;/span&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-8773525885765467781?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/8773525885765467781/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=8773525885765467781' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8773525885765467781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/8773525885765467781'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/ajax-para-supercampeones-o-sabremos.html' title='AJAX PARA SUPERCAMPEONES o ¿Sabremos alguna vez qué es AJAX? (III)'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_uUP4eiIAPJ8/RoqS5xn1ISI/AAAAAAAAAJ0/gQfwXuh3qps/s72-c/Ajax11.gif' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7937747086454198043</id><published>2007-07-02T22:08:00.000Z</published><updated>2007-07-07T03:47:11.737Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='J2EE'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Instalación del Servidor de Aplicaciones</title><content type='html'>&lt;blockquote&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Actualización 04/07/07:&lt;/span&gt; Tras escribir este post, me he dao cuenta que la última versión del servidor de aplicaciones de Sun y de los EJB presentan algunas diferencias clave con respecto a la versión que yo había manejado y de la que os iba a hablar. Para empezar, hasta la versión anterior a la que os he indicao como instalar, se proporcionaba con ella una herramienta de despliegue llamada "deploytool" que en la nueva versión ha sido sustituída por un pack para NetBeans 5.5 u opcionalmente un pluguin para Eclipse, trastearé con ellos antes de escribir cómo hacerlo. También, la programación de los EJB 3.0 presenta algunas diferencias con respecto a su versión anterior en cuanto al número de interfaces a implementar por el/la programador/a y alguna notación específica a utilizar. Dejadme un tiempecillo que lo trastee todo y ya os escribo más adelante.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Y vamos al lío. Ya vimos en el &lt;a href="http://nidea-soluciones.blogspot.com/2007/06/j2ee-programacin-de-servidores-de.html"&gt;anterior post&lt;/a&gt; la teoría mínima sobre J2EE y EJB's que nos iba a hacer falta para saber qué tenemos entre manos, pero sólo con la teoría, y más aún en este caso, no se puede saber de qué se está hablando concretamente, hace falta algo de código, así que en este post la intención era que desarrolláramos y desplegaremos un bean de sesión...peeeeeero, cuando me he puesto a escribir este post me he dao cuenta que ya se hacía demasiao largo sólo con la instalación y configuración del servidor de aplicaciones así que he decidío pasar al siguiente post el desarrollo de nuestro primer bean.&lt;br /&gt;&lt;br /&gt;Lo primero de todo será pues arrancar nuestro servidor de aplicaciones. Pero...¿qué servidor es ese?&lt;br /&gt;Bien, vamos a descargárnoslo de la página de Sun. Yo voy a hacer todo el proceso bajo GNU/Linux, concretamente sobre una Kubuntu 7.04, pero ésto es extrapolable de forma inmediata a cualquier otro sistema Linux y descargándose la versión correcta, también a cualquier sistema Windows. No os recomiendo usar Windows, pero allá vosotros/as :).&lt;br /&gt;&lt;br /&gt;Entramos en &lt;a href="http://java.sun.com/"&gt;http://java.sun.com&lt;/a&gt; y vamos hasta la página de descarga de la última versión de Java EE SDK disponible, junto con el JDK. Para ahorraros la tarea, aquí tenéis un link &lt;a href="http://java.sun.com/javaee/downloads/index.jsp"&gt;http://java.sun.com/javaee/downloads/index.jsp&lt;/a&gt;. Ahí pincháis en &lt;span style="font-style: italic;"&gt;Download with JDK&lt;/span&gt;, luego en &lt;span style="font-style: italic;"&gt;Accept License Agreement&lt;/span&gt; y finalmente sobre la versión de nuestro SO, lo que descargará un fichero autoinstalable donde elijamos. Este fichero contiene entre otras cosas el Java EE SDK y el servidor de aplicaciones de Sun, que son los dos elementos que nos hacen falta.&lt;br /&gt;&lt;br /&gt;Una vez lo tenemos en nuestro sistema de ficheros, le damos permisos de ejecución con un simple &lt;span style="font-style: italic;"&gt;chmod +x nombre_del_ejecutable&lt;/span&gt;. Para ejecutarlo hacemos ./nombre_del_ejecutable y se lanzará un instalador gráfico muy intuitivo. Ya sabéis, siguiente, siguiente, siguiente, meto el sitio donde quiero instalarlo, acepto lincencia, siguiente, siguiente... :). Haciendo eso llegaremos a una pantalla donde tenemos que meter el nombre de usuario del administrador y su contraseña. Importante que os acordéis de este nombre y contraseña. Como siempre, no lo apuntéis en ningún lao salvo que estéis pensando en comeros el papel donde se apunte en breves o que se trate de una región cifrada de vuestro sistema de ficheros. La cosa se vería tal que así:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj7It-Qo8I/AAAAAAAAABc/pIrcb3lIFWY/s1600-h/Instalacion1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj7It-Qo8I/AAAAAAAAABc/pIrcb3lIFWY/s320/Instalacion1.png" alt="" id="BLOGGER_PHOTO_ID_5082588306685862850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Como veis, también tendréis que meter los puertos en los que escuchará nuestro servidor de aplicaciones. Si los puertos por defecto los tenéis ocupados por otra aplicación cambiadlos a vuestro gusto o símplemente por el hecho de añadir un poco más de seguridad al asunto colocándolos en puertos que no sean los habituales (sí, ya se que herramientas como nmap permiten escanear alegremente los puertos activos de una máquina, pero está bien poner las cosas un poco más complicás siempre). Yo como voy a instalarlo y desinstalarlo hoy mismo, voy a dejarlo por defecto. El siguiente paso, pulsar en &lt;span style="font-style: italic;"&gt;Install now&lt;/span&gt;. Lo siguiente ya lo conocéis, una barra de progreso de 0% a 100%, algo como...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj-rt-Qo9I/AAAAAAAAABk/XCndPZWEmto/s1600-h/Instalacion2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj-rt-Qo9I/AAAAAAAAABk/XCndPZWEmto/s320/Instalacion2.png" alt="" id="BLOGGER_PHOTO_ID_5082592206516167634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;y que cuando acabe nos mostrará la página final que además contiene información útil...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj-9t-Qo-I/AAAAAAAAABs/WgFwhfY2UiI/s1600-h/Instalacion3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/Roj-9t-Qo-I/AAAAAAAAABs/WgFwhfY2UiI/s320/Instalacion3.png" alt="" id="BLOGGER_PHOTO_ID_5082592515753812962" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;La información que ahí aparece es especialmente útil porque indica cuál es la orden para arrancar el servidor, que vendrá a ser algo así como...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/sitio/donde/lo/hayais/instalao/bin/asadmin start-domain domain1&lt;/span&gt; (por defecto se crea el dominio llamado domain1)&lt;br /&gt;...pero antes deberíamos establecer una variable de entorno llamada JAVA_HOME que apuntara al sitio donde tengamos instalao un JDK (Java Development Kit). Si hemos escogío la opción de descarga que os dije tenéis uno en el subdirectorio jdk dentro de la nueva instalación. A continuación incluiremos la subcarpeta JAVA_HOME/bin dentro de la variable PATH de nuestro sistema. Dependiendo del tipo de intérprete que usemos ésto se hará escribiendo en un terminal:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;export JAVA_HOME=/sitio/donde/lo/hayais/instalao/jdk&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;export PATH=${PATH}:${JAVA_HOME}/bin&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;...ó...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;setenv JAVA_HOME /sitio/donde/lo/hayais/instalao/jdk&lt;/code&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;setenv PATH ${PATH}:${JAVA_HOME}/bin&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Además también deberíamos de introducir en el PATH una variable que apunte a la localización de los scripts de nuestro servidor, que se habrán instalado en una subcarpeta /bin de nuestra instalación, algo así como...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;export J2EE_HOME=/sitio/donde/lo/hayais/instalao&lt;/code&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;code&gt;export PATH=${PATH}:${J2EE_HOME}/bin&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;...ó...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;setenv JAVA_HOME /sitio/donde/lo/hayais/instalao&lt;/code&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;code&gt;setenv PATH ${PATH}:${JAVA_HOME}/bin&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y finalmente dado que nuestro servidor de aplicaciones necesitará de una base de datos, vamos a establecer la variable CLASSPATH apuntando a un fichero *.jar que permite manejar la BBDD Derby que viene con la instalación de nuestro servidor. Lo tendréis en una subcarpeta llamada /javadb o similar. Ésta variable también tendrá que apuntar al fichero *.jar de J2EE así como al fichero *.jar que apunte a las utilidades de derby. Ésto lo hacemos con un...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;export CLASSPATH=${J2EE_HOME}/lib/j2ee.jar:${J2EE_HOME}/javadb/lib/derbyclient.jar:${J2EE_HOME}/javadb/lib/derbytools.jar&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;...ó...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;setenv CLASSPATH ${J2EE_HOME}/lib/j2ee.jar:${J2EE_HOME}/javadb/lib/derbyclient.jar:${J2EE_HOME}/javadb/lib/derbytools.jar&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Personalmente os recomiendo que para no tengáis que hacer ésto siempre que queráis arrancarlo, os creéis un pequeño script que os lo haga automáticamente, de hecho, ya que ésto lo haréis cuando vayáis a arrancar el servidor de aplicaciones, lo mejor es que en el mismo script también arranquéis el servidor con la orden que ya vimos anteriormente. Éste script podría lucir algo así como...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/Roldnt-QpEI/AAAAAAAAACc/Iv5GVHXWM70/s1600-h/Servidorsh.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/Roldnt-QpEI/AAAAAAAAACc/Iv5GVHXWM70/s320/Servidorsh.png" alt="" id="BLOGGER_PHOTO_ID_5082696591401329730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Con ésto establecer las variables necesarias y arrancar o parar nuestro servidor sería tan fácil como llamar a nuestro script de la forma adecuada. Imaginemos que nuestro script lo hemos llamao servidor.sh.&lt;br /&gt;Para arrancar nuestro servidor de aplicaciones haríamos...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;source servidor.sh arrancar&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;...y para pararlo haríamos...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;code&gt;source servidor.sh parar&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;¿fácil no?&lt;br /&gt;&lt;br /&gt;Si nuestra máquina fuese a funcionar de servidor de aplicaciones de forma permanente podríamos introducir este script en el runlevel adecuado del arranque de nuestro sistema GNU/Linux para que siempre que arranque la máquina se llame a este script y de forma automática se arranque el servidor. Si lo vamos a usar en un PC de escritorio para pruebas, podríamos crear un lanzador en nuestro entorno gráfico para que con un click se arrancase. Si lo vamos a arrancar y parar de forma periódica a determinadas horas se puede colocar una llamada al script en el cron de la máquina, etc, etc, etc...y así podéis buscar mil formas para facilitar la tarea y no tener que hacer ésto ná más que una vez.&lt;br /&gt;&lt;br /&gt;El pantallazo de arranque podía ser éste que os muestro a continuación.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/RolBGN-QpDI/AAAAAAAAACU/T-XxRRULUh4/s1600-h/Arranque_Servidor.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/RolBGN-QpDI/AAAAAAAAACU/T-XxRRULUh4/s320/Arranque_Servidor.png" alt="" id="BLOGGER_PHOTO_ID_5082665229550134322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Para comprobar que hemos arrancado bien nuestro servidor, abrimos un navegador y entramos en http://localhost:8080. Deberíamos ver algo como ésto.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_Odz8IS0Tz3k/RolA8d-QpBI/AAAAAAAAACE/D0-U1jklH8A/s1600-h/Pantalla_Servidor.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_Odz8IS0Tz3k/RolA8d-QpBI/AAAAAAAAACE/D0-U1jklH8A/s320/Pantalla_Servidor.png" alt="" id="BLOGGER_PHOTO_ID_5082665062046409746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Por último, para entrar en la herramienta de administración, entraremos desde nuestro navegador en la dirección http://localhost:4848 y veremos algo como ésto.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/RolAut-Qo_I/AAAAAAAAAB0/r3x6cBvhebs/s1600-h/Pantalla_Administracion1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/RolAut-Qo_I/AAAAAAAAAB0/r3x6cBvhebs/s320/Pantalla_Administracion1.png" alt="" id="BLOGGER_PHOTO_ID_5082664825823208434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Aquí es donde entra en juego el nombre de usuario y la contraseña que escribisteis en un papel para ahora coméroslo. Metéis nombre de usuario de administrador, que en mi caso era admin, contraseña, y os saldrá la página de administración del servidor de aplicaciones, que tendrá una pinta parecida a ésta.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/RolA09-QpAI/AAAAAAAAAB8/VwRZebUKm0E/s1600-h/Pantalla_Administracion2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/RolA09-QpAI/AAAAAAAAAB8/VwRZebUKm0E/s320/Pantalla_Administracion2.png" alt="" id="BLOGGER_PHOTO_ID_5082664933197390850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Por supuesto, si hemos cambiado los puertos de administración o web al instalar el servidor, tendremos que coherentemente cambiar las URLs a las que accedemos para ello.&lt;br /&gt;&lt;br /&gt;Por último, vamos a parar el servidor porque ya nos hemos hartao de tenerlo encendío y no lo vamos a usar más. El resultado de llamar a nuestro script con el parámetro "parar" será tan escueto como éste que sigue.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Odz8IS0Tz3k/RolBA9-QpCI/AAAAAAAAACM/VBFMovmNfOY/s1600-h/Parada_Servidor.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Odz8IS0Tz3k/RolBA9-QpCI/AAAAAAAAACM/VBFMovmNfOY/s320/Parada_Servidor.png" alt="" id="BLOGGER_PHOTO_ID_5082665139355821090" border="0" /&gt;&lt;/a&gt;Y nada más. Espero que después de ésto tengáis en vuestra máquina un bonito servidor de aplicaciones J2EE activo y preparao pal desarrollo de vuestros beans. Ahora sólo nos falta configurarlo a nuestro gusto, pero eso es algo que haremos en el siguiente post para el desarrollo de nuestro primer bean.&lt;br /&gt;&lt;br /&gt;A descansar chavalinos/as que ya os estamos dando mucho curro entre Manolo y yo (como si no supiera que el único que va a leer ésto vas a ser tú, Manolo ;) ).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7937747086454198043?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7937747086454198043/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7937747086454198043' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7937747086454198043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7937747086454198043'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/instalacin-del-servidor-de-aplicaciones.html' title='Instalación del Servidor de Aplicaciones'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_Odz8IS0Tz3k/Roj7It-Qo8I/AAAAAAAAABc/pIrcb3lIFWY/s72-c/Instalacion1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7761956905653890050</id><published>2007-07-02T08:37:00.000Z</published><updated>2007-07-02T15:14:37.123Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>AJAX para CAMPEONES o ¿Qué es eso del AJAX? (Segunda Parte)</title><content type='html'>&lt;div style="text-align: justify;"&gt;Como su nombre indica, en este post continuo con el anterior de &lt;a href="http://nidea-soluciones.blogspot.com/2007/06/qu-es-eso-del-ajax.html"&gt;¿Qué es eso del AJAX?&lt;/a&gt;. Si no lo habéis leido, leedlo para cogerle el hilo a este. En este post vamos a tratar el tema del que denominé como&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="color: rgb(255, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;AJAX PARA CAMPEONES&lt;/span&gt;,&lt;/span&gt; es decir, la programación a pelo, vía Javascript, de las llamadas asíncronas y de toda nuestra lógica del lado de cliente. Empecemos pues.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;Lo primero: las herramientas&lt;/span&gt;&lt;br /&gt;Si empezasteis a trastear un poco con el ejemplo del post anterior, os daríais cuenta que la programación con Javascript es muy puñetera, cualquier mínimo fallo en una letra y nada funciona y a ver quién es el guapo que sabe dónde está el fallo. Javascript adolece de falta de herramientas para trabajar con él y nos podemos tirar horas delante de un código sin saber que leñe falla y sin la menor ayuda. Sin embargo (aquí vengo en plan salvador de los programadores) existen varias herramientas que nos pueden ayudar en nuestra ardua tarea:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.getfirebug.com/"&gt;Firebug:&lt;/a&gt; extraordinario complemento de Firefox que nos permite inspeccionar todo el HTML, el Javascript, el DOM, las hojas de estilo. Podemos depurar el código Javascript, ponerle puntos de interrupción, etc. Una &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;herramienta indispensable&lt;/span&gt; para los campeones del AJAX.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.aptana.com/"&gt;Aptana IDE&lt;/a&gt;: un entorno de desarrollo, aunque también existe como plugin de &lt;a href="http://www.eclipse.org/"&gt;Eclipse &lt;/a&gt;para el desarrollo de Javascript. Es magnífico y tiene un puñado de funcionalidades buenísimas: autocompletado, ayuda dinámica, nos dice la compatibilidad de exploradores para cada método, depuración, etc. También incluye las librerías &lt;a href="http://developer.yahoo.com/yui/"&gt;YUI&lt;/a&gt;, &lt;a href="http://dojotoolkit.org/"&gt;Dojo&lt;/a&gt;, &lt;a href="http://mochikit.com/"&gt;Mochikit&lt;/a&gt;, &lt;a href="http://openrico.org/"&gt;Rico&lt;/a&gt; y &lt;a href="http://www.aflax.org/"&gt;AFLAX&lt;/a&gt; listas para trabajar con ellas (de esto hablaremos en un post posterior).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Por supuesto, antes de empezar, tened dispuesto Internet para consultar las múltiples dudas que os vayan saliendo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;En fin, no queda &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;más remedio, vamos al lío&lt;/span&gt;&lt;br /&gt;En el post anterior vimos un pequeño ejemplo de una llamada básica a servidor para obtener un fichero de texto. En ese caso, lo único que hacíamos era llamar al servidor y poner el texto en un div. Vamos a extender un poco este concepto con otro ejemplo. En este caso ponemos una caja de texto donde el usuario introduce el nombre, pulsa el botón y se realiza una llamada a servidor que devuelve "Te devuelvo tu nombre:" seguido del nombre. Este ejemplo tiene tres particularidades:&lt;ol&gt;&lt;li&gt;Cuando el usuario pulsa el botón aparece un cartel de espera, indicando al usuario que se está cargando la página&lt;/li&gt;&lt;li&gt;He introducido un delay en servidor de 2 segundos para que se aprecie el cartel de espera.&lt;/li&gt;&lt;li&gt;Se han mejorado las funciones de creación del objeto XMLHttpRequest y la de envio de la petición (ahora veremos en qué).&lt;/li&gt;&lt;/ol&gt;El ejemplo lo podéis ver aquí:&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAJAX/pruebaAjax2.html"&gt;http://www.nidea-solucio&lt;/a&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAJAX/pruebaAjax2.html"&gt;nes.com/PruebasAJAX/PruebaAjax2.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;En este caso he llevado las funciones generales (la de creación del objeto y envío de la petición) a un fichero javascript independiente llamado FuncionesAJAX.js. Veamos en primer lugar este fichero y cómo han cambiado las funciones:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/Rojhihn1INI/AAAAAAAAAJM/xTWahkfTU38/s1600-h/Ajax6.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/Rojhihn1INI/AAAAAAAAAJM/xTWahkfTU38/s400/Ajax6.gif" alt="" id="BLOGGER_PHOTO_ID_5082560162744836306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La función ObjetoAjax() la hemos cambiado en el sentido de que ahora contempla todas las posibles inicializaciones que existen. La función EnviarPetición acepta ahora 5 argumentos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;objetoAjax:&lt;/span&gt; será el objeto que inicialicemos con la función anterior. Se inicializa fuera de esta función para que podamos lanzar múltiples comunicaciones a la vez a través de objetos distintos.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;método: &lt;/span&gt;tendremos que poner si queremos hacer un "GET" o un "POST".&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;url:&lt;/span&gt; dirección del servicio web o página o recurso con el que queremos comunicarnos.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;async:&lt;/span&gt; true si queremos que la llamada sea asíncrona o false en el caso que no. Si es asíncrona tendremos que definir un método que maneje la vuelta.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;callback:&lt;/span&gt; nombre del método que manejará la vuelta. La función EnviarPetición se encargará de enganchar la petición con este manejador y pasarle como parámetro el objeto XMLHttpRequest utilizado.&lt;/li&gt;&lt;/ul&gt;Como veis, esta función es mucho más general que la anterior y con ella podremos hacer mejor las cosas.&lt;br /&gt;&lt;br /&gt;Veamos ahora el código de la página PruebaAjax2.html, la primera parte, dentro de la etiqueta HEAD es:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/Rojk-xn1IOI/AAAAAAAAAJU/bzemBAFVhrE/s1600-h/Ajax7.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/Rojk-xn1IOI/AAAAAAAAAJU/bzemBAFVhrE/s400/Ajax7.gif" alt="" id="BLOGGER_PHOTO_ID_5082563946611024098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En esta parte incluimos el script FuncionesAJAX.js y seguidamente definimos dos funciones:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;CargaURL():&lt;/span&gt; esta función es la que inicializa el objeto Ajax, pone visible el panel de espera y llama al método EnviarPeticion. Como veis, llamamos a una página .aspx pasándole como parámetro el nombre. La página devuelve un flujo con el texto. Esta llamada se podría realizar a cualquier página o servicio web que hubiésemos programado nosotros en cualquier lenguaje. Cuidado con intentar llamar directamente a páginas de otro dominio diferente de donde tengáis las páginas u os saltará un error al abrir la conexión. Esto se llama &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;LLAMA&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;DAS CROSS-DOMAIN&lt;/span&gt;, y no se pueden hacer directamente, hay que utilizar un proxy o elementos intermedios.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;FinCargaURL(objeto):&lt;/span&gt; es la función que maneja la respuesta del servidor. Cuando nos responde el servidor, esconderemos el panel de espera y pondremos el texto en el div correspondiente. Ved cómo se pasa como argumento el objeto Ajax encargado de la comunicación.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;La parte del BODY de la página es:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/Rojm8Rn1IPI/AAAAAAAAAJc/Qi16s-n_5KA/s1600-h/Ajax8.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/Rojm8Rn1IPI/AAAAAAAAAJc/Qi16s-n_5KA/s400/Ajax8.gif" alt="" id="BLOGGER_PHOTO_ID_5082566102684606706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En esta parte definimos únicamente la disposición de los elementos. Tenemos el div pnlEspera que contiene la etiqueta de espera, al que le ponemos en el estilo display:none para que inicialmente no se vea. Este ejemplo está bien porque, por lo menos, le ponemos un cartel al usuario diciéndole que algo estamos haciendo (sin demasiada información, pero bueno). Por supuesto esto es muy mejorable y remarco los siguientes aspectos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;El usuario puede volver a pulsar sobre el botón mientras se está haciendo la llamada&lt;/span&gt;. En determinadas circunstancias esto no debe poderse hacer. Imaginad una operación crítica que se realiza varias veces porque el usuario le ha dado al botón sin parar.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;La información proporcionada en el cartel no es demasiado explícita.&lt;/span&gt; Habrá determinados momentos en los que se realicen operaciones largas, de varios pasos, y haya que informar al usuario de por donde va el tema.&lt;/li&gt;&lt;/ul&gt;Por esto, pasamos al siguiente ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 153, 0);font-size:130%;" &gt;Por Dios, más no, por favor&lt;/span&gt;&lt;br /&gt;Pues si, un poco más de Javascript a pelo. En este ejemplo (el tercero del total si no me falla la cuenta), deshabilitamos el botón que realiza la llamada mientras estamos en ello. Podéis ver el ejemplo en la siguiente url:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax3.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax3.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Mola, verdad? Lo único que hacemos es deshabilitar el botón en la función CargaURL y habilitarlo en la función FinCargaURL. Veamos el código:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RokLdRn1IQI/AAAAAAAAAJk/fl7hp4hibCA/s1600-h/Ajax9.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RokLdRn1IQI/AAAAAAAAAJk/fl7hp4hibCA/s400/Ajax9.gif" alt="" id="BLOGGER_PHOTO_ID_5082606252038889730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Le ponemos la propiedad "disabled" a true y luego la volvemos a cambiar a false. Ya empezamos a darle un poquillo de forma al tema, cuidando un poco los detalles, aunque, pequeños saltamontes, el camino aún no ha terminado y es largo y duro.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo, le hemos &lt;span style="font-weight: bold;"&gt;incluido un contador de tiempo&lt;/span&gt;, que se inicia de forma que el usuario sabe cuánto tiempo tarda en volver la información.  Lo podéis ver en:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax4.html"&gt;http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax4.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Aunque no tiene mucha utilidad si que sirve para ilustrar que &lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;podemos mostrar información en pantalla mientras se realiza la llamada&lt;/span&gt;, de verdad es asíncrona. En este caso hemos puesto un contador, pero podría ser cualquier tipo de información. En un ejemplo posterior veremos cómo ir diciéndole al usuario en qué estado se encuentra la operación (para poder darle más información). El código Javascript de esta página se complica un poco más:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RokVNhn1IRI/AAAAAAAAAJs/Wjm2xuW3-GA/s1600-h/Ajax10.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RokVNhn1IRI/AAAAAAAAAJs/Wjm2xuW3-GA/s400/Ajax10.gif" alt="" id="BLOGGER_PHOTO_ID_5082616976572227858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Jugamos en este caso con la función setInterval de Javascript que ejecuta cada x milisegundos la función que le pasemos como argumento. La función clearInterval para este ciclo.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;Final, por ahora...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Como, otra vez, se me está haciendo demasiado largo el post, finalizo aquí. En posteriores post trataremos los siguientes casos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Múltiples llamadas a la vez&lt;/li&gt;&lt;li&gt;Información del estado al usuario&lt;/li&gt;&lt;li&gt;Llamadas Cross-Domain&lt;/li&gt;&lt;li&gt;Utilización de Frameworks que nos ayuden en nuestro camino con AJAX.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7761956905653890050?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7761956905653890050/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7761956905653890050' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7761956905653890050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7761956905653890050'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/07/ajax-para-campeones-o-qu-es-eso-del.html' title='AJAX para CAMPEONES o ¿Qué es eso del AJAX? (Segunda Parte)'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_uUP4eiIAPJ8/Rojhihn1INI/AAAAAAAAAJM/xTWahkfTU38/s72-c/Ajax6.gif' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-4116372329114703646</id><published>2007-07-01T22:29:00.000Z</published><updated>2007-07-01T20:28:14.339Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='servidores'/><category scheme='http://www.blogger.com/atom/ns#' term='J2EE'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>J2EE, programación de servidores de aplicaciones</title><content type='html'>¿Qué? ¿cómo andamos?&lt;br /&gt;&lt;br /&gt;Se que dije que el siguiente post sería de XMLSchema pero voy a dejarlo pa más tarde y me dedicaré hoy a hablar un poquillo por encima de la tecnología J2EE (Java 2, Enterprise Edition). Haré una introducción teórica en este primer post de una serie de 4 post en los que trataré lo que os quiero presentar de la siguiente forma:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Introducción teórica a vista de pájaro de Java 2, Enterprise Edition (J2EE) y sus Enterprise Java Beans (EJB).&lt;/li&gt;&lt;li&gt;Creación de un EJB (I): Session Bean.&lt;/li&gt;&lt;li&gt;Creación de un EJB (II): Entity Bean.&lt;/li&gt;&lt;li&gt;Creación de un EJB (III): Message-Driven Bean.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:180%;" &gt;J2EE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si tuviéramos que, como en el colegio, hacer teoría de conjuntos y ver qué conjuntos es menor que cuál o está contenido en o chorrás desas, tendríamos que decir que:&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;J2ME &amp;lt; J2SE &amp;lt; J2EE&lt;/span&gt;&lt;/div&gt;Y es que si bien J2ME no es exactamente un subconjunto de J2SE o J2EE puesto que puede tener elementos que no aparecen en éstos, sí que cuanto menos es una edición mucho más reducida del entorno de desarrollo.&lt;br /&gt;&lt;br /&gt;Los objetivos básicos con los que surge J2EE son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Abstraer las tareas críticas y repetitivas mediante servicios con una interfaz uniforme.&lt;/li&gt;&lt;li&gt;Preparar una infraestructura uniforme y de una arquitectura software basada en ella para aplicaciones empresariales.&lt;/li&gt;&lt;/ul&gt;La tecnología de J2EE utiliza la filosofía de la programación basada en componentes, más que la orientada a objetos. En este tipo de programación, un componente es algo más amplio que un mero objeto, y más asociado a la aplicación.&lt;br /&gt;&lt;br /&gt;Además, una aplicación compleja basada en componentes a su vez se subdivide en niveles lógicos, de forma que cada nivel cubra un área de tareas y que pueden componer una o varias partes. Así obtenemos "Thin Clients", frente a los "Fat Clients" de la arquitectura Cliente/Servidor, ya que en los niveles intermedios se delega parte de la responsabilidad del servidor. Cada nivel se comunica sólo con los niveles contiguos mediante interfaces bien definidas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:180%;" &gt;EJB's&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Pero pasemos de to este movidón teórico y metámonos en más teoría pero por lo menos un poco más próxima a la práctica. Veamos el concepto de beans. Los beans son nuestros colegas, nuestras "habichuelas", las entidades mínimas de nuestro diseño de aplicaciones...y de servidores de aplicaciones. &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaYG9-Qo7I/AAAAAAAAABU/eCgXcNpZaFU/s1600-h/EJBs_interrelacion.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaYG9-Qo7I/AAAAAAAAABU/eCgXcNpZaFU/s320/EJBs_interrelacion.jpg" alt="" id="BLOGGER_PHOTO_ID_5081916475016520626" border="0" /&gt;&lt;/a&gt;En esencia son clases java con unas ciertas propiedades que permitirán darnos algunas prestaciones en función de nuestras necesidades, o más técnicamente &lt;span style="font-style: italic;"&gt;son componentes que pueden ser usados para construcción de aplicaciones distribuídas y que encapsulan una parte de la lógica de negocio de una aplicación&lt;/span&gt;. Un EJB accede a otros gestores de recursos como bases de datos u otros EJB's y puede ser accedido por otros EJB's, aplicaciones, servlets y aplicaciones cliente. el EJB reside en un contenedor que le provee de servicios de seguridad, transacciones, gestión del ciclo de vida, gestión de concurrencia y despliegue.&lt;br /&gt;&lt;br /&gt;Un EJB (salvo en el especial caso de los Message-Driven Beans) tiene varias partes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);"&gt;La interfaz cliente&lt;/span&gt;. Permite el uso síncrono por parte de los clientes de los procesos de negocio que modela el EJB. Consta de dos clases de tipo &lt;span style="font-style: italic;"&gt;interface&lt;/span&gt;. La &lt;span style="font-weight: bold;"&gt;Home Interface&lt;/span&gt; que debe extender la clase &lt;span style="font-style: italic;"&gt;EJBHome&lt;/span&gt; y controla los métodos del ciclo de vida y la &lt;span style="font-weight: bold;"&gt;Remote Interface&lt;/span&gt; que debe extender la clase &lt;span style="font-style: italic;"&gt;EJBObject&lt;/span&gt; y controla el acceso a los métodos de negocio remotamente.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;"&gt;La clase Enterprise Bean&lt;/span&gt;. Implementa el Bean en sí, su funcionamiento interno, las llamadas a las BBDD necesarias, los métodos de negocio, ciclo de vida, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);"&gt;El descriptor de despliegue&lt;/span&gt;. Proporciona al contenedor toda la información que éste necesita sobre el EJB (nombre, nombre de sus interfaces, tipo de EJB, servicios que se esperan del contenedor, etc). Se trata de un fichero XML, y debido a su complejidad y su extensión se suelen utilizar herramientas de despliegue que lo creen a partir de la selección de opciones en un interfaz gráfico por parte del desplegador.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Lo que nuestros coleguitas beans pretenden ayudarnos a modelar son lo que llamamos "&lt;span style="font-weight: bold;"&gt;entidades de negocio&lt;/span&gt;" y "&lt;span style="font-weight: bold;"&gt;procesos de negocio&lt;/span&gt;", que viene a ser una forma empresarial de llamar a &lt;span style="font-weight: bold;"&gt;información de nuestra aplicación&lt;/span&gt; y &lt;span style="font-weight: bold;"&gt;métodos de acceso y modificación de esa información&lt;/span&gt;. Para que nos entendamos, las entidades de negocio son las bases de datos donde los procesos de negocio son los métodos/funciones/procedimientos que acceden a esas bases de datos y leen o modifican lo que en ellas hay.&lt;br /&gt;&lt;br /&gt;Y para eso, ¿en qué nos ayudan los beans? Pues bien, tenemos beans para cada una de nuestras necesidades en una apliación...beans a la carta. En esencia tenemos:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;"&gt;Beans de Sesión (Session Beans):&lt;/span&gt;&lt;br /&gt;Se encargan de la parte del lado servidor de la lógica de negocio de una aplicación.&lt;br /&gt;Se crean instancias de un Session Bean cuando se produce una petición de un cliente y su tiempo de vida es el de el proceso abierto. Podemos tenerlos de dos tipos:&lt;br /&gt;&lt;ul style="color: rgb(0, 153, 0);"&gt;&lt;li&gt;Beans de sesión sin estado (Stateless Session Beans)&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;No guardan información del cliente. Todos los Stateless Session Beans instanciados tienen la misma identidad.&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Beans de sesión con estado (Statefull Session Beans)&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Presentan diferentes estados en función del cliente, estado que se pierde cuando se deja de usar el Session Bean. Como consecuencia, cada objeto Session Bean tiene distinta identidad.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="border: 0.3em dotted rgb(0, 102, 102); background: rgb(153, 204, 102) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 51, 51); opacity: 0.5;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;Algunas propiedades&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Su estado se mantiene en memoria principal durante una transacción pero pasa a almacenamiento secundario tras desactivarse. Además su estado es inaccesible para otros programas, aunque pueda ser sincronizado para las transacciones.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Sólo puede usarse por un mismo cliente, no puede ser compartida su referencia.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Frente a fallos no se garantiza que una referencia a un objeto Session Bean siga valiendo.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;Los Session Beans son especialmente adecuados para encargarse...&lt;br /&gt;...de la lógica de sesión de una aplicación web...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaMT9-Qo5I/AAAAAAAAABE/N9y3hpjqkko/s1600-h/session_beans_aplicaciones.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaMT9-Qo5I/AAAAAAAAABE/N9y3hpjqkko/s320/session_beans_aplicaciones.jpg" alt="" id="BLOGGER_PHOTO_ID_5081903504215286674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;...o también para encargarse de la lógica de sesión de una aplicación de tres capas.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaNH9-Qo6I/AAAAAAAAABM/eVF9eQFk22U/s1600-h/session_beans_aplicaciones_multicapa.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Odz8IS0Tz3k/RoaNH9-Qo6I/AAAAAAAAABM/eVF9eQFk22U/s320/session_beans_aplicaciones_multicapa.jpg" alt="" id="BLOGGER_PHOTO_ID_5081904397568484258" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;"&gt;Beans de Entidad (Entity Beans):&lt;/span&gt;&lt;br /&gt;Este tipo de beans son los que nos modelan aquéllos conceptos u objetos de negocio cuyos datos deben ser persistentes, para lo que se suele usar una base de datos. Se pueden usar por varios clientes de forma conjunta y simultánea. Su identidad es tan simple como la clave primaria de la base de datos usada. Son tan persistentes que incluso llegan a sobrevivir a caídas de la máquina o de la máquina virtual de Java. En función de quién controle esta persistencia, se clasifican en dos tipos distintos:&lt;br /&gt;&lt;ul style="color: rgb(0, 153, 0);"&gt;&lt;li&gt;Persistencia manejada por el bean (Bean Managed Persistence)&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;El programador del bean debe programar los métodos que aseguran la persistencia, que vienen a ser los métodos que guardan los datos en la base de datos, así como crear la base de datos y mapear variables con columnas de la base de datos.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Persistencia manejada por el contenedor (Container Managed Persistence)&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;El programador queda liberado de la tarea de programar la persistencia teniendo únicamente que indicar al contenedor qué variables van a asociadas a qué columnas de la base de datos para que éste controle la persistencia. Todo este mapeo se reflejará en el fichero xml descriptor del bean.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="border: 0.3em dotted rgb(0, 102, 102); background: rgb(153, 204, 102) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 51, 51); opacity: 0.5;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;Algunas propiedades:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;El estado de un Entity Bean es mantenido en una BBDD, con caché en memoria durante una transacción. Por consiguiente, cualquier programa externo puede acceder a él mediante queries SQL. Además su estado se cambia con transacciones y se puede recuperar en cualquier momento.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Un objeto Entity Bean puede ser compartido por múltiples clientes pasándose la referencia sin problemas.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Frente a fallos, caídas del contenedor o de la máquina, las referencias a los objetos siguen siendo válidas.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;"&gt;Beans controlados por mensajes (Message-driven Beans):&lt;/span&gt;&lt;br /&gt;Este tipo de beans permiten a las aplicaciones J2EE procesar mensajes asíncronos, lo que los diferencia de los anteriores cuya llamada era síncrona. En última instancia no son más que escuchadores de mensajes JMS. Su estructura de hecho es similar a la de los escuchadores de eventos de java, sólo que éstos lo que escuchan son mensajes.&lt;br /&gt;La principal diferencia a nivel de uso de éste tipo de bean con los anteriores es que el acceso a ellos no se realiza mediante interfaces, sino por:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mensajes enviados por algún componente J2EE (una aplicación cliente, otro EJB o un componente web).&lt;/li&gt;&lt;li&gt;Mensajes enviados por una aplicación o sistema JMS que no use la tecnología J2EE.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;También a diferencia de los demás beans, los MDB sólo se componen de una clase java, ya que no tienen interfaces.&lt;br /&gt;describamos entonces algunas de las propiedades de este tipo de EJB's:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Una instancia a un MDB no almacena datos o estado conversacional de ningún cliente.&lt;/li&gt;&lt;li&gt;Todas las instancias de MDB tienen la misma identidad, por lo que la asignación de una instancia a un cliente es indiferente de qué instancia sea.&lt;/li&gt;&lt;li&gt;Un único MDB puede procesar mensajes procedentes de múltiples clientes.&lt;/li&gt;&lt;/ul&gt;Cuando un mensaje llega, el contenedor de nuestro EJB llama a su método &lt;span style="font-style: italic;"&gt;onMessage()&lt;/span&gt;, que típicamente lo primero que debe tener programado es la clasificación de este mensaje según pertenezca a cada uno de los 5 tipos de mensajes JMS, para luego procesarlo según la lógica de negocio de nuestra aplicación.&lt;br /&gt;&lt;br /&gt;Y bueno, yo creo que como introducción a J2EE y EJB's ya se ha hecho demasiao larga, pero weno, espero haberos ayudao en familiarizaros en esta tecnología. El siguiente post irá dedicao a programar y desplegar un Session Bean pa que le echéis un ojo a su código y veáis que hacerlo es más o menos sencillico aunque un poco coñazo. Además usaremos alguna herramienta de despliegue de EJBs que provee Sun. ya os contaré.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 204, 51); font-weight: bold;font-size:180%;" &gt;+info:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/javaee/5/docs/tutorial/doc/"&gt;http://java.sun.com/javaee/5/docs/tutorial/doc/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/javaee/5/docs/firstcup/doc/toc.html"&gt;http://java.sun.com/javaee/5/docs/firstcup/doc/toc.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/javaee/index.jsp"&gt;http://java.sun.com/javaee/index.jsp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-4116372329114703646?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/4116372329114703646/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=4116372329114703646' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/4116372329114703646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/4116372329114703646'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/06/j2ee-programacin-de-servidores-de.html' title='J2EE, programación de servidores de aplicaciones'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_Odz8IS0Tz3k/RoaYG9-Qo7I/AAAAAAAAABU/eCgXcNpZaFU/s72-c/EJBs_interrelacion.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-3647119707189747877</id><published>2007-06-27T15:18:00.000Z</published><updated>2007-06-29T10:22:25.659Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>¿Qué es eso del AJAX?</title><content type='html'>&lt;div style="text-align: justify;"&gt;Algunos pensarán que el AJAX es un equipo de fútbol holandés, otros pensarán que les da igual qué es lo que es, otros pensarán que tiene algo que ver con internet (nos vamos acercando al tema). En este post voy a intentar dar una primera idea que, si puedo iré extendiendo en sucesivos posts, de qué es realmente AJAX y qué podemos hacer con él.&lt;br /&gt;&lt;br /&gt;La definición es:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;AJAX: Asynchronous Javascript and XML&lt;/blockquote&gt;&lt;br /&gt;muy bien, y esto ¿qué significa?&lt;br /&gt;&lt;br /&gt;Empezaré contando mi pequeña historia con AJAX, mi experiencia con AJAX comenzó cuando un conocido me comentó que estaban haciendo un sistema web con ATLAS. Yo pensé "¿para qué meter un atlas en un sistema web?", luego me enteré que ATLAS es una implementación de ASP.NET para AJAX. A estas alturas aún no sabía qué era AJAX. Con el tiempo empecé a investigar por mi cuenta y a jugar con diferentes lenguajes de programación y frameworks javascript: programé con PHP, utilicé el GWT (Google Web Toolkit) para Java, enredé con el framework Dojo y Rico, programé con ASP.NET, etc. En fin que me mareé viendo herramientas y programando con ellas, pero, realmente ¿QUÉ ES AJAX?&lt;br /&gt;&lt;br /&gt;Mi último proyecto, con el que estoy ahora mismo (aprovecho para comentarlo) es un portal libre para compartir cursos de formación (&lt;a href="http://learning.nidea-soluciones.com/"&gt;http://learning.nidea-soluciones.com&lt;/a&gt;) es donde más he trabajado con AJAX y todas las técnicas relacionadas, así que, vamos al lío de verdad.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-weight: bold;font-size:130%;" &gt;¿Qué es AJAX?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;AJAX no es ni más ni menos que un mecanismo que nos permite realizar llamadas asíncronas al servidor desde un página web. Así suena muy poca cosa, pero en realidad abre todo un mundo de posibilidades (y problemas...).&lt;br /&gt;&lt;br /&gt;¿Cómo eran las cosas antes de AJAX? Antes de AJAX, una página web se componía de etiquetas HTML y de etiquetas de servidor (utilizadas por el lenguaje de programación). Cada vez que un usuario realizaba cualquier acción en una página web que requiriese de la actualización de su contenido, se ponía la pantalla en blanco (mientras se realizaba la comunicación con el servidor) y luego volvía a aparecer con la actualización puesta. ¿Por qué pasaba esto? porque lo que los navegadores entienden es el HTML, y las etiquetas de servidor las debe sustituir el servidor por HTML con los datos correctos. Veamos el siguiente ejemplo:&lt;br /&gt;&lt;br /&gt;Tenemos una página simple programada en ASP.NET (es lo que tengo más manío):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/RoKLcxn1III/AAAAAAAAAIk/wMT_BpYFCtw/s1600-h/ajax1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/RoKLcxn1III/AAAAAAAAAIk/wMT_BpYFCtw/s400/ajax1.gif" alt="" id="BLOGGER_PHOTO_ID_5080776656100335746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lo único que hace esta página es pedir un nombre y al pulsar sobre el botón, pone el nombre que se ha escrito en una etiqueta. Sin embargo, éste lenguaje no es entendido por el navegador, por lo que el servidor web, lo que hace es sustituir las etiquetas &lt;asp:&gt; por lo que corresponda en HTML. La primera vez que se ve la pági&lt;/asp:&gt;&lt;asp:&gt;na, el código enviado es:&lt;/asp:&gt;&lt;br /&gt;&lt;asp:&gt;&lt;/asp:&gt;&lt;br /&gt;&lt;asp:&gt;&lt;/asp:&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RoKNyBn1IJI/AAAAAAAAAIs/82asyBdZcdM/s1600-h/ajax2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RoKNyBn1IJI/AAAAAAAAAIs/82asyBdZcdM/s400/ajax2.gif" alt="" id="BLOGGER_PHOTO_ID_5080779220195811474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Todas las etiquetas &lt;asp:&gt; han sido sustituidas por sus correspondientes etiquetas HTML. Si el usuario introduce un nombre y pulsa sobre el botón "btnBoton" que pone Púlsame, la página se tendrá que recargar para que aparezca el nombre en la etiqueta "lblNombre". El servidor (porque se le indica así en el fichero de código que a&lt;/asp:&gt;&lt;asp:&gt;compaña a esta página) devolverá la siguiente página:&lt;/asp:&gt;&lt;br /&gt;&lt;asp:&gt;&lt;/asp:&gt;&lt;br /&gt;&lt;asp:&gt;&lt;/asp:&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/RoKOsxn1IKI/AAAAAAAAAI0/5DNp1lAHIas/s1600-h/ajax3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/RoKOsxn1IKI/AAAAAAAAAI0/5DNp1lAHIas/s400/ajax3.gif" alt="" id="BLOGGER_PHOTO_ID_5080780229513126050" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La página devuelta tiene en la caja de texto el nombre "Manolo" y en el span también. Al pulsar el botón, &lt;span style="font-weight: bold; color: rgb(204, 102, 0);font-size:130%;" &gt;hemos tenido que ir al servidor para que recompusiese el HTML y lo enviase de vuelta al navegador&lt;/span&gt;. El tiempo que tarde en llegar la petición al servidor, en que éste evalúe las acciones, obtenga los resultados, rehaga el HTML y llegue de vuelta al navegador, será el tiempo que esté nuestro explorador en blanco. Esto es así porque las operaciones son &lt;span style="color: rgb(255, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;SÍNCRONAS&lt;/span&gt; &lt;/span&gt;(lo remarco porque este es el quid de la cuestión).&lt;br /&gt;&lt;br /&gt;Lo que nos permite AJAX es lanzar una llamada asíncrona al servidor para que nos envíe la información que requiramos de vuelta, sin que el usuario pierda el control de la interfaz de usuario. Como me gustan mucho los dibujos, veámoslo en uno de ellos:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_uUP4eiIAPJ8/RoS_SBn1ILI/AAAAAAAAAI8/SEe5xbCl8ms/s1600-h/Ajax4.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_uUP4eiIAPJ8/RoS_SBn1ILI/AAAAAAAAAI8/SEe5xbCl8ms/s400/Ajax4.gif" alt="" id="BLOGGER_PHOTO_ID_5081396595974807730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En el primer caso, se realiza una llamada a &lt;a href="http://www.nidea-soluciones.com/"&gt;http://www.nidea-soluciones.com&lt;/a&gt; (os la marco por si queréis visitarla). El servidor web devuelve el HTML de la página, el explorador lo lee y lo pinta en la pantalla. Si el usuario pulsa algún botón o realiza alguna acción que requiera una respuesta del servidor (actualización de una parte de la página), se enviará una petición de actualización al servidor y perderemos el control en el explorador, la página se quedará en blanco esperando que el servidor recomponga todo el HTML y se lo envíe de vuelta. Este tiempo variará dependiendo del servidor, de las líneas de comunicación y de lo que queramos actualizar. En ocasiones puede llegar a ser muy frustrante puesto que no sabemos si se ha colgado el sistema, si la línea se ha caído, por dónde va el proceso, etc. y actualizamos la página para volver a darle o nos salimos del sitio.&lt;br /&gt;&lt;br /&gt;En el segundo caso utilizamos AJAX en nuestra página web y el proceso varía ligeramente. La primera llamada al servidor nos devuelve la página web, igual que el ejemplo anterior. Sin embargo, a partir de ese momento, todas las peticiones de actualización de partes de la página se realizan con llamadas asíncronas a servidor. Esto lo que hace es lanzar una &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;hebra de ejecución diferente&lt;/span&gt; de la que tiene el control de la página y, esta hebra, contacta con el servidor y le pide la información. En Javascript, habremos implementado &lt;span style="font-weight: bold; color: rgb(255, 153, 0);"&gt;un manejador para el evento de recepción de la respuesta&lt;/span&gt;. Cuando llegue la respuesta se ejecutará el código de ese manejador, donde le diremos qué tiene que hacer con los datos que nos envía el servidor. Durante el tiempo de ida y venida al servidor, la hebra principal mantiene el control de la página, posibilitando que el usuario siga haciendo cosas con ella. Podría realizar más peticiones a servidor y se lanzarían nuevas hebras.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;Hasta aquí muy bien pero, ¿y eso cómo leñe se hace?&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;La primera alternativa para trabajar con AJAX es la que denomino, &lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;AJAX PARA CAMPEONES&lt;/span&gt;. La pongo en mayúsculas y coloreado porque esta opción es la de trabajar a pelo con Javascript y con el objeto XmlHttpRequest (que veremos ahora). Esta alternativa es un poco sádica pero creo que es necesario que sepáis realmente cómo funciona. Una vez superado este nivel podremos trabajar con la opción &lt;span style="font-weight: bold;"&gt;AJAX COMODO&lt;/span&gt;, en la que utilizaremos algún framework de los existentes.&lt;br /&gt;&lt;br /&gt;Vamos a ver un ejemplo práctico (aquí iba a poner un ejemplo pero Blogger me bloquea las llamadas asíncronas), por lo que podéis ver el ejemplo en:&lt;br /&gt;&lt;a href="http://www.nidea-soluciones.com/PruebasAJAX/PruebaAJAX1.html"&gt;http://www.nidea-soluciones.com/PruebasAJAX/PruebaAJAX1.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;En este ejemplo, al pinchar en el enlace lo que se hace es inicializar el objeto xmlHttpRequest (encargado de realizar la llamada asíncrona) y hacer un GET asíncrono a &lt;a href="http://www.nidea-soluciones.com/PruebasAJAX/prueba.txt"&gt;http://www.nidea-soluciones.com/PruebasAJAX/prueba.txt&lt;/a&gt; El texto de respuesta lo coloca en una etiqueta que está justo debajo del enlace. Veamos el código:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_uUP4eiIAPJ8/RoTWWRn1IMI/AAAAAAAAAJE/2kylOtC3FTs/s1600-h/Ajax5.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_uUP4eiIAPJ8/RoTWWRn1IMI/AAAAAAAAAJE/2kylOtC3FTs/s400/Ajax5.gif" alt="" id="BLOGGER_PHOTO_ID_5081421957756690626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Si nos fijamos en la parte BODY, tenemos un hipervínculo que al pulsarlo lanza la función CargaTexto(), hecha en Javascript, y tenemos un SPAN llamado textoAjax. Vamos a ver las tres funciones Javascript que hemos definido:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Función ObjetoAjax():&lt;/span&gt; función encargada de inicializar el objeto XMLHttpRequest para poder realizar llamadas asíncronas a servidor. Esta función comprueba el tipo de explorador porque Firefox e Internet Explorer utilizan diferentes inicializaciones para este objeto (como siempre...).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Función CargaTexto():&lt;/span&gt; esta es la función que se invoca cuando el usuario hace clic sobre el enlace. Esta función realiza tres cosas distintas:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Utiliza el objeto Ajax para abrir una conexión GET con la URL http://www.nidea-soluciones.com/PruebasAJAX/prueba.txt.&lt;/li&gt;&lt;li&gt;Declara cuál va a ser la función que se ejecute cuando llegue la respuesta a la llamada al servidor. En este caso, dicha función va a ser capturaPeticion.&lt;/li&gt;&lt;li&gt;Lanza la llamada.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Función CapturaPeticion(): &lt;/span&gt;cuando se recibe la respuesta se lanza esta función que lo que hace es poner el texto de la respuesta en la etiqueta SPAN definida.&lt;br /&gt;&lt;br /&gt;Este ejemplo es muy básico pero ilustra bastante bien el ciclo de llamada y respuesta de AJAX. Siempre tendremos estas tres funciones: una que inicializa el objeto, una que realiza la llamada y otra que recibe la respuesta. En sucesivos posts iremos viendo cómo podemos mejorar este ejemplo (ya está siendo muy largo este), como por ejemplo:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Etiquetas de espera para que el usuario sepa que algo se está haciendo.&lt;/li&gt;&lt;li&gt;Control de la concurrencia en servidor.&lt;/li&gt;&lt;li&gt;Deshabilitar controles a la hora de ir a servidor.&lt;/li&gt;&lt;li&gt;Informe del estado de la operación&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;Estas son cosas importantes que hay que tener en cuenta a la hora de programar con AJAX, porque al introducir el elemento asíncrono, se incrementa la complejidad en nuestros desarrollos.&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:130%;" &gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Finalmente, ¿qué NO es AJAX?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;También es importante saber qué no es AJAX. AJAX es, simplemente, la posibilidad de realizar llamadas asíncronas a servidor. De ésto se pueden derivar muchas herramientas y controles, los llamados rich-controls, que utilizan AJAX. Podremos implementar grids que carguen los datos dinámicamente utilizando el objeto XMLHttpRequest y funciones Javascript, ventanas modales que carguen información, etc. Todos estos controles utilizan AJAX y CSS para ayudarnos en nuestros desarrollos, pero AJAX sólamente es el objeto XMLHttpRequest.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-3647119707189747877?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/3647119707189747877/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=3647119707189747877' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/3647119707189747877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/3647119707189747877'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/06/qu-es-eso-del-ajax.html' title='¿Qué es eso del AJAX?'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_uUP4eiIAPJ8/RoKLcxn1III/AAAAAAAAAIk/wMT_BpYFCtw/s72-c/ajax1.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-279159040670649891</id><published>2007-06-22T00:57:00.000Z</published><updated>2007-06-30T13:13:40.860Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='DTD'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>¿Otro post no? XML for Mayor!</title><content type='html'>Como veo que la cosa está más muerta que un cordero la noche después del fin del Ramadán digo...¿voy a escribir no? ... pero ... ¿qué coño escribo?&lt;br /&gt;&lt;br /&gt;Pues como últimamente he estao aprendiendo cosillas sobre XML, RDF, RDFa, JDOM, DOM, SAX, XML-RPC, SOAP, XSLT, SNMP, J2EE, J2ME, BGP, IPv6, y demás parafernalias (cómo mola escribir siglas, no importa que no tengas puta idea, quedas como un señor poniéndolas ;) ), pos me he decidío a contaros un poquillo de estas tecnologías en diferentes post por entregas. Si os aburro no tenéis más que decirlo.&lt;br /&gt;&lt;br /&gt;Y pa empezar, vamos a introducirnos levemente en el maravilloso mundillo del XML.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;blockquote&gt;Actualización(23/06/07): &lt;span style="color: rgb(0, 0, 0);"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;Como los feeds (orígenes, RSS, como los queráis llamar) se envían mediante XML, paradojas de la vida, quien lea este post recibiéndolo desde un agregador probablemente no lo lea bien porque interpretará el código XML y el resultado será que no se le mostrarán las etiquetas, sólo su contenido. Por ello, por el momento y a estas alturas de la noche no se me ocurre más que entrar vía web para leerlo sin problemas. Mil perdones. ¿A alguien se le ocurre una solución?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-size:180%;" &gt;XML&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Mi descubrimiento de XML como metalenguaje para "casi todo" ha sido como encontrarse con un hermano perdido. Uno se pregunta...¿cómo coño no lo vi antes? ¿he estao tirando to este tiempo a la basura?&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&lt;span style="font-size:130%;"&gt;¿De ande ha salío ésto?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;XML surge más o menos como una simplificación de SGML, que viene a ser un lenguaje un tanto más ambíguo pero mucho más extenso y rico. SGML se lo inventaron por allá por los "unites estates" cuando un grupo de editoriales decidieron que los autores tenían que definir el contenido de forma lógica mientras los editores se dedicaran a la presentación física que es pa lo que al fin y al cabo les pagan :). Así después de unos cuantos quebraderos de cabeza se llega a un estándar ISO con una especificación muuuuy compleja. Pero claro, esto pa los libros y un grupo reducido de gente dispuesta a andarse con rodeos está mu bien, pero pa Internet digamos que la cosa estaba chunga. Así surge una simplificación que aprovechaba la experiencia previa de SGML para orientarlo a Internet y que permitía fácilmente la definición de nuevos lenguajes (de ahí el eXtensible de "eXtensible Markup Language"). Sobre todo, lo que se buscaba era un lenguaje que fuese fácil de procesar, y a la vista está que lo consiguieron. Podíamos decir que con XML se consiguió un 80% de la funcionalidad de SGML con sólo un 20% de su complejidad. Todo un logro, ¿verdad?&lt;br /&gt;&lt;br /&gt;Pa no confundirnos, y como a alguno ésto le puede sonar a HTML aclaremos que&lt;br /&gt;XML == SGML--&lt;br /&gt;pero...&lt;br /&gt;XML != HTML++&lt;br /&gt;&lt;br /&gt;Aunque la sintaxis XML pueda recordarnos a HTML (de hecho las versiones actuales de HTML son ya XML, más concretamente se le llama XHTML), XML presenta algunas diferencias con el tradicional HTML de to la vida. Algunos ejemplos son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;En HTML podíamos alegremente cerrar y abrir las etiquetas donde nos diese la gana, e incluso algunas ni cerrarlas, por lo que se suponía &lt;code&gt;&amp;lt;/p&amp;gt;&lt;/code&gt; por defecto. En XML ni de coña. Cada etiqueta que se abra debe ser cerrada adecuadamente, e importando y mucho el orden. Así mientras en HTML podíamos escribir &lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;i&amp;gt;jeje&amp;lt;/i&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;, en XML no se puede en aras de un procesamiento más simple y de más claridad.&lt;/li&gt;&lt;li&gt;Mientras en HTML los valores de los atributos podían o no ir entre "", en XML es estrictamente obligatorio que lo hagamos.&lt;/li&gt;&lt;li&gt;En HTML podíamos dejar un atributo vacío sin cerrar, pero en XML todo elemento se cierra. Por ejemplo:&lt;br /&gt;(HTML) &lt;code&gt;&amp;lt;img src="http://www.blogger.com/..."&amp;gt;&lt;/code&gt;&lt;br /&gt;(XML) &lt;code&gt;&amp;lt;img src="http://www.blogger.com/..." /&amp;gt;&lt;/code&gt; (nótese que pa ahorrarse el curro de volver a poner la etiqueta con "/" delante, si el elemento es vacío se puede poner el símbolo "/" antes de cerrarlo).&lt;/li&gt;&lt;/ul&gt;Dicho ésto vamos a ver un ejemplo sencillico XML y sobre él ya vamos trabajando.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&lt;span style="font-size:130%;"&gt;Veamos qué pinta tiene&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE empresa SYSTEM "empresa.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Definición de una empresa emprendedora, "así tó wapa" podíamos definirla--&amp;gt;&lt;br /&gt;&amp;lt;empresa clase="wenaquetecagas" contacto="nidea@nidea-soluciones.com"&amp;gt;&lt;br /&gt;&amp;lt;nombre&amp;gt;N-IDEA. Nuevas Ideas&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;lt;url tipo="web"&amp;gt;http://www.nidea-soluciones.com&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;url tipo="blog"&amp;gt;http://nidea-soluciones.blogspot.com&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;direccionpostal&amp;gt;C/ Tejuela, 25. Alcalá la Real (Jaén). CP: 23680&amp;lt;/direccionpostal&amp;gt;&lt;br /&gt;&amp;lt;/empresa&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Como véis, es bastante intuitivo. Yo defino lo que quiero y con la lógica que yo quiero imprimiéndole semántica a lo que escribo. De hecho sin saber programar una persona que leyera el código de arriba muy probablemente comprendería el mensaje. Ésa es la idea.&lt;br /&gt;&lt;br /&gt;Pero vamos a lo que nos ocupa. Bueno, aquí tenemos varias cosas. Primero tenemos&lt;br /&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"&amp;gt;&lt;/code&gt;&lt;br /&gt;Ésta es lo que se llama una "processing instruction", pero además es una especial. Es la que debe contener todo documento XML al principio. Ántes de ella no se puede escribir nada, ni siquiera comentarios, para que el documento sea válido. Las processing instruction sirven para pasarle información a la aplicación que usa el documento XML. Normalmente su sintaxis es:&lt;br /&gt;&lt;code&gt;&amp;lt;?Programa Instrucciones?&amp;gt;&lt;/code&gt;&lt;br /&gt;Como por ej: &lt;code&gt;&amp;lt;?JAVA_OBJECT JAR_FILE="/nidea/mijar.jar"?&amp;gt;&lt;/code&gt;&lt;br /&gt;Por supuesto, para no confundir al bicho, está prohibido empezar la processing instruction con "xml" ya que este nombre está reservado para el principio del documento como habéis visto.&lt;br /&gt;Lo que sigue a "xml" son dos atributos de nombre version y encoding, y de valores 1.0 y UTF-8 respectivamente. Aunque os lo podéis imaginar, son la versión y la codificación del documento. La version es obligatoria que sea 1.0 (creo), y que aparezca siempre, pero la codificación puede no aparecer o puede ser distinta. Por ejemplo, un tipo de codificación muy típica es la ISO-8859-1 que viene a ser la que define los caracteres españoles específicamente. La UTF-8 es también llamada Unicode-8 y es la que he usao en este caso.&lt;br /&gt;&lt;br /&gt;Siguiente cosa rara que vemos es...&lt;br /&gt;&lt;code&gt;&amp;lt;!DOCTYPE empresa SYSTEM "empresa.dtd"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Es una etiqueta especial ya que como se puede observar no sigue la sintaxis de xml para las etiquetas. No va cerrada, el nombre de la etiqueta comienza por ! en lugar de por letra o "_" y tiene espacios. Entonces...¿qué #!*+ es? Pues se trata de la definición del tipo de documento. Como ésto es sólo una breve introducción no entraré en detalles, pero es necesario saber que debe apuntar al elemento raiz del documento xml (lo que sigue a !DOCTYPE, en nuestro caso empresa) y al DTD del documento, que viene a ser un fichero que especifica la estructura de nuestro documento xml, qué elementos pueden ir dentro de otros, qué tipo de datos se acepta en cada elemento, cuántas veces puede aparecer un elemento, etc. Pero eso ya lo veremos luego. En nuestro caso, el DTD está en la misma carpeta del documento xml y se llama "empresa.dtd".&lt;br /&gt;&lt;br /&gt;Después vemos un comentario. Es eso de...&lt;br /&gt;&lt;code&gt;&amp;lt;!-- Definición de una empresa emprendedora, "así tó wapa" podíamos definirla--&amp;gt;&lt;/code&gt;&lt;br /&gt;Pos eso, se trata de un comentario. Algo que el/la programador/a escribe para que no sea interpretado por los programas que hagan uso del documento, pero que puede servir para hacer más legible el mismo o para explicar algunos detalles específicos a otros/as programadores/as que puedan leer nuestro xml. En ocasiones también se usa para ocultar elementos a los programas. En fin, usarlos mola, pero no usarlos no hace tu documento no válido.&lt;br /&gt;&lt;br /&gt;Y luego viene el documento en sí, con sus etiquetas, sus atributos y demás. De eso creo que poco hay que explicar. La cosa está en imaginar de forma lógica la información que queremos representar y luego escribirla con coherencia. Si queremos representar en un documento una empresa que puede ser de varias clases y que tendrá un único e-mail de contacto, una forma de representarlo sería con la que escogí arriba:&lt;br /&gt;&lt;code&gt;&amp;lt;empresa clase="wenaquetecagas" contacto="nidea@nidea-soluciones.com"&amp;gt;&amp;lt;/empresa&amp;gt;&lt;/code&gt;&lt;br /&gt;pero ahí ya está vuestra imaginación y el tipo de datos que queráis representar. Si además sabemos que una empresa tiene un nombre, nos podemos inventar un nuevo elemento que esté dentro de "empresa" y cuya etiqueta sea "nombre". Si sabemos que la empresa tendrá urls de varios tipos y múltiples, una fórmula puede ser crear otros tantos elementos también dentro de "empresa" de etiqueta "url" y con un atributo "tipo" que defina el tipo de url que es (página web, blog, wiki...). Si por último sabemos que las empresas representadas por este tipo de documento pueden tener una dirección postal que queramos representar, nos podemos imaginar un último elemento "direccionPostal" que almacene esta información. Pero lo que os dije antes, todo es imaginar e inventar. Ahí los creadores sois vosotros/as.&lt;br /&gt;&lt;br /&gt;Bueno, visto un ejemplo práctico sobre el que habremos visto la dinámica de XML, vamos a ver algunas cuestiones específicas de los elementos y los atributos.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&lt;span style="font-size:130%;"&gt;Elementos y Atributos&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Los elementos deben comenzar su nombre por letra o underscore (_) seguido de alguna combinación de letra, underscore, números, puntos, dos puntos o guiones. No puede contener espacios en blanco y no puede comenzar por "xml" en ninguna de sus variantes (xml, xmL, xMl, xML, Xml, XmL, XMl o XML). En principio no existe longitud máxima para el nombre aunque hay que tener cuidado con algunos parsers de nivel superior que puedan tenerlo.&lt;br /&gt;&lt;br /&gt;Los atributos se definen en la etiqueta de comienzo de un elemento. Definen pares nombre="valor". No pueden estar duplicados dentro de la misma etiqueta, usan para su nombre las mismas reglas que los elementos y son obligatorias las comillas para determinar el valor. Como es lógico, el símbolo de las comillas (") no puede aparecer en el valor del atributo, para lo cual se utilizará la entidad predefinida &amp; quot; (sin el espacio entre &amp; y quot;. No lo junto porque entonces vuestro navegador os lo mostraría como " y entonces habríamos hecho un pan con unas hostias).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="font-size:180%;"&gt;DTD&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Veamos lo último que nos falta para poder definirnos nuestro lenguaje XML a nuestro gusto. Pongamos que vamos a definir un nuevo lenguaje que llamaremos NideaML.&lt;br /&gt;Como hemos visto antes, NideaML es un lenguaje sencillico y que sirve para definir una empresa dado su nombre, clase, correo-e de contacto, urls de varios tipos y dirección postal. Si dejáramos nuestro documento anterior tal cual eliminando la sentencia de !DOCTYPE, ya no sería NideaML, sería XML normalico y corriente porque no existirían restricciones que impidieran a nadie meter otros atributos en el documento o inventarse nuevos elementos, o no colocarlos en su debido orden. Si no hay DTD, se asume que cualquier cosa puede ir dentro de cualquier cosa y se admite cualquier tipo de elemento. ¿Pero cómo podemos añadir estas restricciones? Como ya os dije antes, para eso está aquí nuestro amigo el DTD.&lt;br /&gt;&lt;br /&gt;Como antes, no hay mejor forma de aprender algo en cualquier tipo de programación que viendo algo programado, así que os mostraré cómo quedaría el DTD llamado empresa.dtd, que quedaría como sigue...&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;!ELEMENT empresa (nombre, url*, direccionPostal?)&amp;gt;&lt;br /&gt;&amp;lt;!ATTLIST empresa&lt;br /&gt;clase CDATA #REQUIRED&lt;br /&gt;contacto CDATA #REQUIRED&amp;gt;&lt;br /&gt;&amp;lt;!ELEMENT nombre (#PCDATA)&amp;gt;&lt;br /&gt;&amp;lt;!ELEMENT url (#PCDATA)&amp;gt;&lt;br /&gt;&amp;lt;!ATTLIST url&lt;br /&gt;tipo (web | blog | wiki | proyecto) "web"&amp;gt;&lt;br /&gt;&amp;lt;!ELEMENT direccionPostal (#PCDATA)&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;¿Qué? ¿Cómo lo veis? ¿Bonito no? :).&lt;br /&gt;Se puede intuir más o menos la sitaxis, pero vayamos poco a poco. De lo primero que ya os habréis percatao es que no se trata de XML, se parece más a nuestro querido !DOCTYPE que al resto de lo que hemos visto.&lt;br /&gt;&lt;br /&gt;Bien, queremos definir qué elementos se permiten, cuáles están dentro de cuáles, qué atributos tienen, si son o no obligatorios y de qué tipo son.&lt;br /&gt;&lt;br /&gt;Empecemos por los elementos. Los elementos se declaran con &lt;code&gt;!ELEMENT&lt;/code&gt; seguido de su nombre y entre paréntesis el tipo de datos que van a contener indicando cuántas veces van a ocurrir. El nombre del elemento sigue las reglas que ya citamos antes, y el tipo de datos que van a contener pueden ser otros elementos (se pone el nombre de éstos), texto normal (#PCDATA), una combinación con expresiones regulares de las anteriores (ej: nombre | #PCDATA | (otroNombre, otroMas) ), cualquier cosa (ANY) o nada (EMPTY).&lt;br /&gt;El número de ocurrencias de cada cosa que puede entrar en nuestro elemento lo definen unos caracteres que se añaden al final del nombre del elemento/expresión regular. Veamos nuestros símbolos para las expresiones regulares:&lt;br /&gt;si no ponemos nada implica que ocurre sólo una vez&lt;br /&gt;+ indica una o más veces&lt;br /&gt;* indica cero o más veces&lt;br /&gt;? indica cero o una vez&lt;br /&gt;() indica agrupamiento&lt;br /&gt;| indica disyunción&lt;br /&gt;, indica secuencia ordenada&lt;br /&gt;Vamos pues a echarle un vistazo a nuestro ejemplo para ver eso qué implica.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;!ELEMENT empresa (nombre, url*, direccionPostal?)&amp;gt;&lt;/code&gt;&lt;br /&gt;Según lo dicho antes, esta declaración define un elemento de nombre "empresa" que puede contener a su vez otros elementos, y sólo otros elementos, no puede tener texto plano; y además estos elementos tienen que ser de tipo "nombre","url" y "direccionPostal"; y además tienen que aparecer en este orden; y además ocurrirá que,&lt;br /&gt;"nombre" aparecerá sólo una vez,&lt;br /&gt;"url" puede aparecer cuantas veces quiera o no aparecer,&lt;br /&gt;"direccionPostal" puede aparecer una vez o no aparecer&lt;br /&gt;&lt;br /&gt;¿Fácil no? Ahora vamos con los atributos&lt;br /&gt;Los atributos se declaran con &lt;code&gt;!ATTLIST&lt;/code&gt; seguido del nombre del elemento al que pertenecen y seguido de la lista de atributos que puede contener este elemento.&lt;br /&gt;La lista de atributos se escribe siguiendo triplas del siguiente modo&lt;br /&gt;nombre_atributo tipo_atributo valor_por_defecto&lt;br /&gt;Ocasionalmente puede ir entre el tipo de atributo y su valor por defecto la obligatoriedad o no de que aparezca el atributo, de modo que&lt;br /&gt;#REQUIRED significa que el atributo es obligatorio&lt;br /&gt;#IMPLIED significa que el atributo no es obligatorio&lt;br /&gt;#FIXED significa que el atributo está fijo al valor que ponemos por defecto y el programador del documento xml no puede modificarlo. Si lo hiciera esta valor es ignorado prevaleciendo el del DTD.&lt;br /&gt;El valor por defecto sólo tiene sentido cuando el atributo es #FIXED o #IMPLIED. En el caso concreto de #FIXED además es obligatorio. La cosa es que si ponemos a un atributo #REQUIRED se supone que es obligatorio, luego el programador pondrá un valor sí o sí, ¿para qué íbamos a darle un valor por defecto si siempre sería machacado por el del programador XML?&lt;br /&gt;Los tipos de datos pueden ser:&lt;br /&gt;CDATA -&gt; Similar al #PCDATA de los elementos.&lt;br /&gt;Enumerated -&gt; Tienen su sintaxis especial, es el que hemos usado en el ejemplo para el atributo "tipo" del elemento "url". Consiste en una expresión de posibles valores separados por (|) donde el programador/a elegirá uno de ellos.&lt;br /&gt;ID -&gt; Asocia al elemento un identificador único.&lt;br /&gt;IDREF -&gt; Referencia a un ID.&lt;br /&gt;IDREFS -&gt; Lista de IDREF separados por espacio.&lt;br /&gt;NMTOKEN -&gt; Especifican identificadores.&lt;br /&gt;NMTOKENS -&gt; Especifican listas de identificadores.&lt;br /&gt;&lt;br /&gt;Si todo esto lo aplicamos a nuestro ejemplo particular...&lt;br /&gt;&lt;code&gt;&amp;lt;!ATTLIST empresa&lt;br /&gt;clase CDATA #REQUIRED&lt;br /&gt;contacto CDATA #REQUIRED&amp;gt;&lt;/code&gt;&lt;br /&gt;...implica que estamos tratando con la lista de atributos del elemento "empresa"; que además puede tener atributos tipo clase o tipo contacto; que además clase son datos normales y corrientes y es obligatoria su aparición; y que además contacto también tendrá como valores datos normales y será obligatoria su especificación en el documento XML.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;!ATTLIST url&lt;br /&gt;tipo (web | blog | wiki | proyecto) "web"&amp;gt;&lt;/code&gt;&lt;br /&gt;...implica que estamos tratando con la lista de atributos del elemento "url"; que además sólo tendrá el atributo "tipo"; que éste podrá ser igual a "web" o "blog" o "wiki" o "proyecto" y que en caso de no encontrarse el valor por defecto será de "web".&lt;br /&gt;&lt;br /&gt;Y bien, yo creo que como introducción a lo que puede ser XML y su definición mediante DTDs, ésto ya está. Ya podéis haceros vuestro lenguaje MiracomomoloML para definir todo lo que se os ocurra. ¿Y para qué? Pues por ejemplo una utilidad muy buena es la de pasarle al documento una hoja de estilo XSLT y transformarlo directamente en una página web con un formato determinado, que puede servirnos para crear páginas web dinámicamente en una máquina a partir de una aplicación que recoja unos datos de un formulario web, o para utilizar sistemas como DOM o JDOM para recorrer la información recogida en el formulario web y convertida a XML y usarla para hacer otra cosa, o para crear apliciones...¡yo qué se! yo ya os he contao como funciona, ahora ¡a buscarle utilidades propias, coño! :).&lt;br /&gt;&lt;br /&gt;Espero que os sea de utilidad. Si así es, prometo volver para contaros un poco de XMLSchema, que vienen a ser los sucesores de los DTD y que permiten más versatilidad y especificidad en las definiciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 204, 0);font-size:130%;" &gt;+info:&lt;/span&gt;&lt;br /&gt;&lt;a style="color: rgb(51, 102, 255);" href="http://www.w3.org/"&gt;http://www.w3.org&lt;/a&gt;&lt;span style="color: rgb(102, 0, 204);"&gt;&lt;br /&gt;&lt;a href="http://www.xml.com/"&gt;http://www.xml.com&lt;/a&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 0, 204);"&gt;&lt;br /&gt;&lt;a href="http://www.xmlinfo.com/"&gt;http://www.xmlinfo.com&lt;/a&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-279159040670649891?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/279159040670649891/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=279159040670649891' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/279159040670649891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/279159040670649891'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/06/otro-post-no-xml-for-mayor.html' title='¿Otro post no? XML for Mayor!'/><author><name>Nacho Foche</name><uri>http://www.blogger.com/profile/00144444954853390223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_Odz8IS0Tz3k/R5zDrjLdkxI/AAAAAAAAAP8/TpdXSb7D3s8/S220/IMG_0423.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-7223233235228766276</id><published>2007-03-29T09:39:00.000Z</published><updated>2007-04-16T09:38:37.039Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='repositorios'/><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='programación'/><title type='text'>Subversion: Colaboración en el Software</title><content type='html'>&lt;div style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;span style="font-size:85%;"&gt;En este artículo vamos a ver el funcionamiento de Subversion, una herramienta libre que sirve como repositorio de código en los proyectos de desarollo software. La utilización de un repositorio de código, un sitio central donde se vayan juntando todas las partes desarrolladas por las diferentes personas involucradas, es obligado. Sin embargo, Subversion nos ofrece una serie de funcionalidades que la convierten en una de las herramientas colaborativas más utilizadas.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;¿Qué es un repositorio?&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Un repositorio de código es, en esencia, un programa que sirve para juntar las partes de código que los desarrolladores programan por separado. Las funcionalidades básicas (aunque no todos las cumplen) son las siguientes:&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Mantener revisiones de código, es decir, si yo cambio algo en el repositorio, el gestor de código debe mantener puntos de restauración, de forma que cualquiera pueda descargarse el código con mis modificaciones o sin ellas.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Seguimiento de Cambios, debo poder realizar comentarios cuando actualice algo, indicando qué es lo que he cambiado, qué es lo que he arreglado, etc. de forma que el resto de desarrolladores puedan consultar mi comentario y saber qué es lo que he hecho antes de descargarselo.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Copias de seguridad de los códigos y las revisiones.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Etiquetas de versiones y revisiones, para poder localizar rápidamente la versión a descargar o la revisión específica.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;¿Por qué utilizar&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt; un r&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;epositorio de código?&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Cuando nos encontramos involucrados dentro de proyectos de desarrollo donde trabajan diversas personas cada una de ellas conocerá una parte del desarrollo y se centrará en ella. Sin embargo, aunque cada uno lleve su parte, necesita la de los demás para que funcione correctamente. Sin un repositorio, tendríamos que enviarnos constantemente todas las partes unos a otros con el consiguiente caos, o que una persona se dedicase a recibir todas las modificaciones y mandarlas al resto de desarrolladores. En el siguiente diagrama se muestra un poco esta situación:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RiM54UdYefI/AAAAAAAAAIM/HiSBzFJ58Yc/s1600-h/Subversion1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RiM54UdYefI/AAAAAAAAAIM/HiSBzFJ58Yc/s400/Subversion1.gif" alt="" id="BLOGGER_PHOTO_ID_5053946846567234034" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En el caso que tengamos un repositorio de código, la situación sería diferente. Cada desarrollador estaría conectado con el repositorio y enviaría sus modificaciones al mismo. Este se encargaría de conjugar las diferentes partes y mostrar a los desarrolladores la versión completa.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Operaciones con los repositorios:&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Existen dos operaciones básicas que se realizan en todos los respositorios y luego algunas funcionalidades avanzadas de algunos mejor preparados, caso de Subversion.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Confirmar:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; subir los cambios que hemos realizado al repositorio. Únicamente se enviarán los cambios realizados con respecto a la versión existente en el repositorio.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Actualizar:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; recibir la versión existente en el repositorio con los cambios que hayan realizado el resto de desarrolladores.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;span style="font-size:85%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_uUP4eiIAPJ8/RiM9BEdYegI/AAAAAAAAAIU/WQOHg4MNzkk/s1600-h/Subversion2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_uUP4eiIAPJ8/RiM9BEdYegI/AAAAAAAAAIU/WQOHg4MNzkk/s400/Subversion2.gif" alt="" id="BLOGGER_PHOTO_ID_5053950295425972738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Las operaciones especiales que tenemos en los repositorios y que le dan un valor añadido son:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Creación de etiquetas y versiones:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; nos permite marcar con una etiqueta una confirmación de cambios o crear una versión, de forma que se pueden localizar rápidamente las revisiones o versiones.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Creación de ramas de desarrollo:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; esta opción permite crear líneas independiente de desarrollo. Esto se utiliza para el desarrollo de partes de las aplicaciones que no queremos que interfieran en la rama principal hasta que estén acabadas. Una vez terminadas, se fusiona la rama de desarrollo con la principal.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Bloqueo de ficheros:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; habrá veces que estemos modificando un fichero y no queramos que nadie lo toque mientras lo tengamos nosotros. En ese caso, bloquearemos el fichero y el repositorio no dejará que nadie lo utilice.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;Fusión de ficheros:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; esta es una de las herramientas más potentes de Subversion ya que permite que varias personas trabajen simultáneamente sobre el mismo fichero, encargándose él de fusionar los cambios. En caso de surgir un conflicto porque varias personas han modificado la misma parte del fichero, tendrá que ser el usuario el que diga cual es la modificación que prevalece.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;span style="font-size:85%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_uUP4eiIAPJ8/RiNAeUdYehI/AAAAAAAAAIc/y8o_F7ji4qc/s1600-h/Subversion3.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_uUP4eiIAPJ8/RiNAeUdYehI/AAAAAAAAAIc/y8o_F7ji4qc/s400/Subversion3.gif" alt="" id="BLOGGER_PHOTO_ID_5053954096472029714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Utilización del repositorio:&lt;/span&gt;&lt;br /&gt;Como en todas las fases de un proyecto, es necesario plantearse una estrategia para la utilización del repositorio. Subversion se basa en carpetas dentro de las cuales se organiza la información. Para acceder al repositorio se puede hacer vía un servidor Apache (utilizando http) o mediante el servidor subversion (protocolo svn). Dentro del servidor accederemos a una carpeta o subcarpeta para actualizar nuestra información. Se aconseja siempre que los ficheros que se mantengan controlados por el repositorio sean los de código fuente, excluyendo ficheros binarios, compilados, librerías, etc. La estructura de carpetas aconsejable es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul style="text-align: justify; font-family: trebuchet ms;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Carpeta TRUNK: rama principal de desarrollo, aquí irá el desarrollo principal y se irán fusionando las diferentes ramas.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Carpeta TAGS: carpeta donde se almacenarán las diferentes versiones y revisiones con nombre del desarrollo. Cuando queramos descargarnos una versión la buscaremos en esta carpeta&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Carpeta BRANCHES: carpeta donde se almacenan las ramas de desarrollo de nuestro sistema.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: trebuchet ms;"&gt;Manteniendo esta simple jerarquía de carpetas será mucho más fácil gestionar nuestro repositorio de código y realizar las copias de seguridad.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-family: trebuchet ms;"&gt;Conclusión:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;La utilización de un repositorio de código es obligado en proyectos que cuenten con más de dos o tres personas trabajando. No solo nos sirven como controlador de los cambios, sino también como copia de respaldo del código. Es muy aconsejable utilizarlos y sacarles el máximo de provecho.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37408564-7223233235228766276?l=nidea-soluciones.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nidea-soluciones.blogspot.com/feeds/7223233235228766276/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37408564&amp;postID=7223233235228766276' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7223233235228766276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37408564/posts/default/7223233235228766276'/><link rel='alternate' type='text/html' href='http://nidea-soluciones.blogspot.com/2007/03/subversion-colaboracin-en-el-software.html' title='Subversion: Colaboración en el Software'/><author><name>Manuel Cardenas Thorlund</name><uri>http://www.blogger.com/profile/06587982094935316828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_uUP4eiIAPJ8/Sk87Q1l-MjI/AAAAAAAAAdM/m7z8ojMeopA/S220/PHOT0001.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_uUP4eiIAPJ8/RiM54UdYefI/AAAAAAAAAIM/HiSBzFJ58Yc/s72-c/Subversion1.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37408564.post-6995060932273152908</id><published>2007-03-18T12:05:00.000Z</published><updated>2007-03-21T10:48:27.017Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='El Marco Lógico'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperación al desarrollo'/><title type='text'>Gestión de Proyectos de Cooperación al Desarrollo</title><content type='html'>&lt;h3&gt;1.Presentación&lt;/h3&gt;   &lt;div class="indent"&gt;El objetivo de esta entrada es introducir una ya conocida herramienta en la gestión de proyectos de cooperación al desarrollo llamada "Enfoque del Marco Lógico" (EML).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;2.Proyectos de desarrollo&lt;/h3&gt;   &lt;strong&gt;¿Qué entendemos por desarrollo?&lt;/strong&gt;&lt;br /&gt;&lt;div class="indent"&gt;Un problema serio que nos encontramos a la hora de elaborar un proyecto de cooperación al desarrollo es que nos lanzamos a desarrollarlo sin habernos parado a pensar seriamente qué entendemos nosotros por desarrollo. ¿Qué es desarrollo? ¿desarrollo económico? ¿desarrollo humano? ¿mejora de las capacidades individuales? ¿mejora de las capacidades colectivas? ¿mejoras puntuales de las condiciones de vida? ¿mejora de las herramientas que generan las condiciones de vida? Es necesario que esto quede claro.&lt;br /&gt;El desarrollo, entendido desde el punto de vista de un proyecto de cooperación al desarrollo siempre ha de ser el de la mejora de las condiciones de vida colectivas, que devendrá en la mejora de las condiciones individuales, desde la óptica del desarrollo humano siempre y salvaguardando los derechos humanos, la justicia social y los derechos colectivos de grupos étnicos y nacionalidades.&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;¿Qué es un proyecto de desarrollo?&lt;/strong&gt;&lt;br /&gt;&lt;div class="indent"&gt;Los proyectos de desarrollo tienen el objetivo de solucionar unos problemas o necesidades y mejorar la situación de los beneficiarios aplicando diversas técnicas y garantizando siempre la independencia de la población beneficiaria así como la dirección activa del proyecto por parte de éstos.&lt;br /&gt;Una de las tareas principales del proyecto debe ser capacitar a sus beneficiarios para que sean más independientes de la ayuda y el apoyo exterior.. que sean capaces de resolver nuevos problemas por sí mismos.&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Estructura de un proyecto de desarrollo&lt;/span&gt;&lt;br /&gt;Un proyecto se estructura en 4 fases principales:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Identificación&lt;/li&gt;&lt;/ul&gt; En esta fase lo que hacemos es determinar los problemas que han de resolverse.. ¿qué sucede?, ¿por qué sucede?, ¿a quiénes y cómo afecta?... ¿cómo se puede solucionar?.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Diseño&lt;/li&gt;&lt;/ul&gt; En la etapa de diseño organizaremos la información obtenida en la fase anterior. Aquí hay que establecer las estrategias a seguir, los plazos, los costes, los recursos necesarios.. ¿qué queremos hacer?, y ¿cómo pretendemos realizarlo? ¿a quién se dirige la acción?, ¿por qué y para qué actuar?, ¿con quién, dónde, cuándo y con qué recursos?&lt;br /&gt;En esta etapa construiremos el esqueleto del proyecto: la llamada Matriz de Planificación del Proyecto, que será nuestra guía a seguir para poder llevar a cabo la fase de Ejecución.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Ejecución&lt;/li&gt;&lt;/ul&gt;Éste es el punto es donde comenzamos a ejecutar el proyecto según lo planificado. Aquí es importante ser flexible y no seguir con rigidez el plan previsto, además de contemplar la identificación de nuevos problemas que pudieran no haberse captado durante las etapas previas.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Evaluación&lt;/li&gt;&lt;/ul&gt; Una vez ejecutado el proyecto, no vale simplemente con recoger los bártulos e irse a otra parte.. Es muy importante realizar un seguimiento posterior, ver si realmente se consiguen los objetivos iniciales de mejorar las condiciones de vida de los beneficiarios. Y aprender de los errores cometidos para mejorar en los próximos proyectos..&lt;br /&gt;&lt;br /&gt;&lt;div class="indent"&gt;Pese a que se plantean como 4 fases diferenciadas, el formato de seguimiento de éstas no es estrictamente lineal sino que sería más bien circular teniendo en cuenta que cuando se detecta un nuevo problema en alguna fase podemos tener que repensar todas las fases anteriores.&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;3.Centrándonos&lt;/h3&gt;   &lt;div class="indent"&gt;En ésta entrada nos vamos a centrar en la fase de Identificación y de Diseño, que son muy importantes pues serán la base de nuestro Proyecto. Si fallamos aquí… es bastante probable que nuestro proyecto se vaya al garete. Desgraciadamente el 30% de los proyectos de cooperación fracasan y el motivo suele ser que fallan en estas fases.&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;¿Qué es el Enfoque del Marco Lógico?&lt;/strong&gt;&lt;br /&gt;&lt;div class="indent"&gt;Para diseñar nuestro proyecto vamos a utilizar la principal herramienta de gestión de proyectos de Desarrollo: El Enfoque del Marco Lógico, convertido ya en método universal de la mayor parte de las agencias de cooperación internacional y que demuestra especial utilidad en las tareas de identificación y gestión de proyectos. De hecho, pese a que ha quedado ya institucionalizada como procedimiento indispensable para solicitar financiación de proyectos de cooperación al desarrollo a agencias y organismos donantes, la herramienta pudiera servir para la identificación y gestión de proyectos de cualquier tipo, no sólo de cooperación al desarrollo.&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;Características del EML&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Nos permite tomar decisiones mejores y más razonadas. &lt;/li&gt;&lt;li&gt; Es un método participativo.. que no se puede llevar a cabo sin tener en cuenta a los beneficiarios. Hay que insistir en que los proyectos no se preparan en un despacho ni de manera individual. Los proyectos se identifican y diseñan en equipo y en el seno de esos equipos deben estar representados los beneficiarios, siempre que eso sea posible. Si olvidamos esa perspectiva, la mayoría de los pasos que vamos a comentar habrán perdido su sentido.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Un problema que presenta el EML es que luego no se lleve a la práctica, uno puede hacer un análisis teórico perfecto e impecable… pero luego en la práctica dejar de hacer muchas de las cosas planificadas y ésto es como un puente al que no se le puede andar quitando pilares así como así, pues se te viene abajo.&lt;br /&gt;&lt;br /&gt;Por ejemplo, imaginad un proyecto en el que se mueven todos los medios para instalar unos equipos de radio que saquen de su aislamiento a unas comunidades. En ocasiones, por falta de tiempo los cooperantes instalan los equipos y luego apenas enseñan a los pobladores a utilizarlos. Si el EML se hace correctamente, esa capacitación forma parte del proyecto, es más, quizás la parte más vital para el funcionamiento correcto del mismo y para su perdurabilidad en el tiempo. Ya sabéis, si no cumples con una determinada etapa, sea cual sea, la estás cagando.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Estructura del EML&lt;br /&gt;&lt;/strong&gt; &lt;div class="indent"&gt;El EML consta de 5 pasos:&lt;br /&gt;&lt;li&gt; Análisis de la participación: Averiguar todos los actores, las relaciones entre ellos y determinar a quién va destinado el proyecto.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Análisis de los problemas: ¿qué problemas tienen los actores?&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Análisis de los objetivos: ¿como se podrían solucionar cada uno de esos problemas?&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Análisis de las alternativas: entre las soluciones anteriores, aquí elegiremos la que llevaremos a cabo.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Matriz de planificación del proyecto: tabla esquemática que resume la identificación del proyecto y facilita enormemente la gestión del mismo.&lt;br /&gt;&lt;/li&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;4. Participación.&lt;/h3&gt;   &lt;div class="indent"&gt;Antes de nada, es necesario conocer la realidad social de la zona donde pretendemos actuar. Y para ello no hace falta ser sociólogo, basta con hablar con la gente y sobre todo.. escucharla. Así podremos descubrir qué inquietudes y problemas tienen y qué grupos están afectados por ellos.&lt;br /&gt;Con el análisis de la participación se pretenden básicamente dos cosas. En primer lugar, se trata de tener una visión, lo más precisa posible, de la realidad social sobre la que el futuro proyecto pretende incidir. Muchas intervenciones de desarrollo fracasan, precisamente, por haber efectuado un diagnóstico excesivamente superficial del contexto en el que deben insertarse.&lt;br /&gt;Un proyecto comienza siempre determinando quienes son los colectivos cuya situación se quiere mejorar.&lt;br /&gt;Es preciso mostrar qué problemas afectan a qué personas, cuáles son las relaciones entre los diferentes grupos que conforman una realidad, entre esos grupos y los problemas identificados y entre los propios problemas que se han detectado, para finalmente alcanzar los criterios que establecen las prioridades para elegir la alternativa considerada más deseable.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;5. Identificación de los actores y árbol de problemas&lt;/h3&gt;   &lt;div class="indent"&gt;Una vez recogidos todos los datos del terreno llega la hora de poner un poco de orden y de analizar la situación que nos hemos encontrado en clave de problemas. Al fin y al cabo el análisis del proyecto depende de varios factores clave:&lt;br /&gt;&lt;li&gt; La calidad de la información disponible.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; La capacidad del equipo del proyecto.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; El nivel de participación de la población beneficiaria y contrapartes locales en el análisis del problema.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; La experiencia previa del equipo.&lt;br /&gt;&lt;/li&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="indent"&gt;Salvo la experiencia previa, el resto de factores dependen de la etapa que acabamos de desarrollar y de cuánto impliquemos a las partes locales en el análisis y procesado de la información que hagamos ahora.&lt;br /&gt;&lt;br /&gt;Comencemos con la identificación de los actores, que van a poder ser de los siguientes tipos:&lt;br /&gt;&lt;li&gt; Gobierno (regional, local, nacional, extranjero, etc).&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Población local (familias, poblaciones, comités, etc).&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Sector privado (cooperativas, PYMEs, grandes empresas, etc).&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Organizaciones no gubernamentales (asociaciones, colectivos, del lugar, del norte, etc).&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Ecosistemas (fauna, flora, lugares protegidos, entornos de vital importancia para supervivencia de poblaciones, etc).&lt;br /&gt;&lt;/li&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="indent"&gt;Si se han identificado correctamente los actores y extraído adecuadamente la información necesaria debiéramos ser capaces de construir la "tabla de análisis de actores", que debiera tener al menos la siguiente profundidad:&lt;/div&gt;&lt;br /&gt;&lt;table style="border: medium dotted ;" border="1"&gt;    &lt;tbody&gt;&lt;tr&gt;        &lt;td&gt;Actores&lt;/td&gt;        &lt;td&gt;Características&lt;/td&gt;        &lt;td&gt;Problema&lt;/td&gt;        &lt;td&gt;Interés&lt;/td&gt;        &lt;td&gt;Potencial&lt;/td&gt;        &lt;td&gt;Inter-relación&lt;/td&gt;    &lt;/tr&gt;    &lt;tr&gt;        &lt;td&gt;Actor 1&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;    &lt;/tr&gt;    &lt;tr&gt;        &lt;td&gt;Actor 2&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;    &lt;/tr&gt;    &lt;tr&gt;        &lt;td&gt;Actor 3&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;    &lt;/tr&gt;    &lt;tr&gt;        &lt;td&gt;Actor 4&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;    &lt;/tr&gt;    &lt;tr&gt;        &lt;td&gt; ... &lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;        &lt;td&gt;&lt;br /&gt;&lt;/td&gt;    &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="indent"&gt;Una vez tenemos ya una buena tabla con todos los actores implicados en nuestro proyecto, sus relaciones, problemas y demás vicisitudes, llegó la hora de construir nuestro árbol de problemas que nos demuestre de forma causal cuáles son los más importantes que han de atajarse para producir un efecto dominó sobre sus derivados. El resultado ha de ser algo parecido a ésto:&lt;/div&gt;&lt;br /&gt;&lt;div class="center"&gt;&lt;h3&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Odz8IS0Tz3k/Rf-cz2yBf3I/AAAAAAAAAAM/Ty_Gzuvvhy8/s1600-h/arbol_problemas.jpeg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Odz8IS0Tz3k/Rf-cz2yBf3I/AAAAAAAAAAM/Ty_Gzuvvhy8/s320/arbol_problemas.jpeg" alt="" id="BLOGGER_PHOTO_I
