Integrando Sistemas de Informacion?

http://sergiot2.com/blogimages/2009/06Jun/20090609-Integration.jpg

En la mayoría de proyectos uno de los retos de alguna u otra forma es intercambiar información con sistemas de terceros, a los cuales no tenemos acceso directamente a su fuente de datos. Un caso común es el intercambio de información con proveedores, con entidades financieras, entidades públicas, o alguna otro tipo de aplicación de terceros. Los comentarios a continuación son basados en los escenarios y proyectos en que participado,  y siempre se pueden complementar con alguna experiencia adicional en los comentarios.

¿Por qué esta necesidad de intercambiar información?

  • Por que nuestro negocio necesita de otras organizaciones para lograr sus metas. Por ejemplo, si tengo un sitio en la que se realizan ventas on-line, podría crear mi propio medio de pago y encargarme de la cobranza, pero perdería la visión de mi negocio: “vender”, lo que puedo hacer para centrar los esfuerzos en mi negocio, es apoyarme en algún medio de cobro ya existente, pero surge una nueva necesidad: intercambiar información con un sistema de cobro.
  • Eliminar la redundancia de información dentro de nuestra organización. La mayoría de organizaciones, sobre todo las grandes, cuentan con empaquetados o software comúnmente llamado ERP. Pero adicionalmente a tener un ERP, también podemos contar sistemas propios, ya sea por que el ERP no se adecua en todas las áreas dentro de mi organización, o por que simplemente no hay presupuesto para comprar los otros módulos. Tener varios sistemas en nuestra organización, crea la necesidad de poder integrar los mismos, para no tener información “duplicada” en cada sistema, y para remover esa redundancia debemos integrar los sistemas.
  • Crear nuevas oportunidades de negocio en nuestra empresa. Digamos que soy una entidad financiera, o soy una empresa que vende electrodomésticos, y que deseo como nueva oportunidad de negocio, vender determinados seguros dentro de mi organización. Una opción simple y práctica para hacerlo, es sólo vender los seguros y no cubrir los siniestros, para eso debemos buscar una compañía de seguros constituida que sea quien cubra los siniestros, y nosotros sólo centrarnos en vender seguros a nuestros clientes. Pero para llevar a cabo ello, tenemos el reto, del área de TI, de integrar mi información de ventas con la aseguradora. Y este reto también es en viceversa, la aseguradora debe tener los mecanismos que me permitan recibir información.
  • Reportar información a sistemas de terceros. Cuando tenemos que reportar información, a entidades públicas reguladoras, o a otros sistemas dentro de la corporación, por ejemplo en el caso que estemos dentro de alguna franquicia.

Y dentro de las opciones de comunicación tenemos hasta tres escenarios comunes de intercambiar información:

  • Manual. En esta opción hay un esfuerzo del área de TI que va recibir la información, ya que debe realizar la aplicación que usarán terceros para ingresar información en su fuente de datos. Por ejemplo, una aseguradora no te va dar un conexión directa a su base de datos, una de las opciones que tienen ellos para vender seguros en organizaciones de terceros, es desarrollar una aplicación que sea usada por todas las empresas quieran vender nuestros seguros. Este escenario también es la principal fuente de datos de un ERP, yo puedo consultar y ingresar información a una fuente de datos de un ERP, a través de su aplicación front-end.
  • Masiva. En muchos casos usar el sistema de terceros para enviarles nuestra información a su fuente de datos, puede no ser la mejor solución debido a problemas de infraestructura, de personalización, o simplemente por que no hay un front-end, para realizar aquello. Una opción es intercambiar información a través de archivos, digamos que al finalizar el día puedo generar un archivo plano que contiene toda la información que deseo ingresar en otra fuente de datos. Esta puede ser la manera más práctica, rápida, fácil e interoperable, de intercambiar información, ya que todos los sistemas operativos soportan los archivos planos, y todos los lenguajes contienen librerías, apis, o clases, para el manejo de archivos, sólo basta con definir una estructura y podemos integrar sistemas. Los empaquetados o ERP, normalmente también deberían permitir carga masiva de información a través de archivos.
  • Automatizada o Directa. Una de las “desventajas” del intercambio de información a través de archivos es que tengo que esperar que estos sean procesados para ver reflejada la información en el sistema. Pero tenemos otra opción  “automatizada” de intercambiar información “on-line”, y es que la organización que va enviar información desarrolle su propio sistema, personalizado con las necesidades del mismo, pero que ingrese directamente información en otra fuente de datos, y para lograr este objetivo necesitamos a los famosos “conectores”, y que cualquier producto empaquetado sea ERP u otro, debería tener, y estos pueden ser conectores limitados (del propio fabricante) o conectores estandarizados, como usar Web Services, y en general cualquier otro “Servicio” que me permita conectarme con una fuente de datos de terceros.

Lo ideal sería que nuestro negocio soporte los tres tipos de comunicación para no perder ninguna oportunidad de crecimiento:

  1. Vayamos al escenario de una organización que fábrica determinados productos electrónicos. La organización, desea aumentar su fuerza de ventas, y para eso tiene pensado elaborar convenios con pequeños proveedores que no tienen un área de TI claramente definida, y que no tienen un sistema de ventas implementado, en este escenario se podría dar desarrollar una aplicación de ventas para los proveedores que quieran vender nuestros productos.
  2. Pero que pasa si hay otros proveedores, que tienen un área de TI definida, y que cuentan con sistemas propios de ventas, una manera simple de recibir la información del proveedor es aceptar la carga masiva a través de archivos, para ello la organización que recibe la información debe definir la estructura, y validación del archivo a intercambiar.
  3. Y finalmente, si hay un proveedor que desea realizar ventas on-line, debido a que en algunos casos se venden productos sin stock, por el tiempo para enviar y procesar un archivo, pero ellos no quieren usar la aplicación de ventas del fabricante, por que tendrían que duplicar la información para que ellos mismos cuenten con la información registrada, en cambio el proveedor quieren realizar una aplicación que registre la venta en su fuente de datos, pero a la vez y de manera automática que registre la venta en la fuente de datos del fabricante, y ahí la necesidad de un conector o Web Services, y en general un servicio, para enviar la información en tiempo real.

Conocer la visión de negocio o el porque de la necesidad de integrar sistemas, es importante para tener claro proceso y los objetivos de integrar información. Ahora vayamos a un punto de vista más técnico, que me permita “integrar sistemas”.

En el primer escenario no hay mucha ciencia, ya es algo común y natural desarrollar aplicaciones, sólo hay que tener en cuenta que la misma puede ser usada por terceros fuera de mi organización. Además que existen que internet podemos encontrar muchos frameworks de desarrollo, o blogs hablando de tips para el desarrollo de aplicaciones. Por eso nos vamos a centrar en los dos últimos escenarios mencionados.

Veamos algunos ejemplos:

  1. Windows Live Product Search, o lo que ahora es Bing Shopping. Si soy una empresa de venta de productos, este servicio me permite promocionar mis productos, es decir va ser un sistema de apoyo a mi negocio. Live Product Search, tenía un servicio para vendedores llamado: Product Upload Service, este servicio me permitía ingresar información en su fuente de datos enviando información en archivos planos o archivos de texto, delimitados por el carácter TAB, un ejemplo sería:

    Product   Descripction  Price  Stock
    Prdo01     Este es un producto muy bueno  34.6  8
    Prdo02     Este es un producto muy barato  24.6  4

    Sólo tengo que enviar mi archivo con todos los productos de mi sistema que deseo publicar, y que serán ingresado en la fuente de datos de ellos, para que ellos puedan promocionarlos en su Web. Google también tiene su Google Product Search, y que también soporta el envío de archivos de texto delimitados por TAB. Además de archivos planos con separación por tab, otro formato común son los archivos CSV, y hasta se puede intercambiar información en archivos usando archivos Excel, pero es 100% recomendable usar archivos de texto, para no limitar el intercambio de información a determinadas tecnologías.

  2. NetSuite. Dentro de una organización puedo tener aplicaciones de 3 terceros, para realizar nuestras operaciones transaccionales más importantes, como la contabilidad. Pero a medida que la organización sigue creciendo necesita del apoyo de otros negocios o sistemas, y para lograr aquello necesitamos personalizar nuestra comunicación con el empaquetado o ERP que usemos, en nuestro ejemplo el producto es NetSuite. Como primera fuente NetSuite nos brinda una aplicación Web, para ingresar información en su fuente de datos. ¿Qué pasa, si quiero consultar directamente a mi información de NetSuite a través de un sistema?, o ¿si quiero manipular la misma?. Digamos que quiero vender mis productos en Amazon, ellos me envían diariamente las ordenes de compra y quiero enviar directamente las ordenes a Netsuite, no manualmente a través de la Web, si no que sea un proceso automático de un sistema propio. Para lograr aquello, NetSuite posee un juego o api de Web Services llamado SuiteTalk, con el cual podemos hacer diversas operaciones contra nuestra información, consulta o modificación, directamente, sin la necesidad de que sea un proceso manual a través de su Front-End. Un caso similar, es con SAP, el cual posee conectores que permite tener acceso a la información de un sistema SAP, hay una implementación para .Net: SAP .NET Connector, y aquí pueden revisar un ejemplo: ASP.NET Using SAP .NET Connector.

Notemos, que nosotros no sabemos que motor de base de datos usa Live Products, Google Products, o NetSuite. Pero ello no impide que con un front-end, un archivo masivo, o un conector, pueda consultar y modificar: “mi información”. Y obviamente estos modelos de negocio de poder acceder directamente a mi información, tiene que ver con el modelo SaaS, pero ese será tema de otras entradas.

Resumiendo, si quiero que otras organizaciones se comuniquen o integren con nuestros sistemas, tenemos 3 opciones:

  1. Desarrollar una aplicación Web o Windows, y que ellos usen la misma para ingresar información directamente en nuestra fuente de datos.
  2. Usar un archivo de carga masiva. Debemos definir: la estructura del archivo, las reglas de validación, y la frecuencia de envío. Y obviamente, soportar la carga masiva a nuestra fuente de datos.
  3. Crear conectores, que pueden ser Web Services u otro Servicio, que permita que terceros puedan desarrollar sus propias aplicaciones, y se ingrese automáticamente la información a nuestra fuente de datos.

Tomemos el punto 3 para hacer algunas aclaraciones. Definamos la siguiente frase: “Un Web Service no es para que te comuniques tu mismo, un Web Services o Servicio es para habilitar que otro sistemas se comuniquen contigo”. Por ejemplo, si en un mismo servidor estará la base de datos, el Web Service, y una la Aplicación Web. Usar un Servicio, Web Services, o WCF para que la aplicación Web se conecte a la base de datos, ¿se justifica la creación de una capa de servicios para pasar información dentro del mismo servidor?, ¿sabiendo que ese Servicio sólo lo usaremos nosotros?, Nuevamente este es un problema de moda, recomendar el uso de WCF sin conocer el escenario puede ser un problema que finalmente terminan sufriendo los desarrolladores duplicando la comunicación, cuando no hay un entorno distribuido y cuando nadie más que nosotros va a usar el servicio. Esto no quiere decir que no debamos usar WCF, debemos usarlo pero cuando la infraestructura lo necesite o cuando necesitemos que terceros se comuniquen con nuestra fuente de datos, y no por que en todos lados hablan de Servicios, Web Services, o WCF. Leer también este artículo de elBruno: la arquitectura de la cebolla, del mismo podemos acotar la siguiente frase: “aplicar la solución correcta al problema específico, y que cuando el mismo cambie o evolucione, en ese momento cambiemos o evolucionemos nuestra solución

Y para cerrar, ya mencionamos algunas opciones para poder integrar sistemas, en los siguientes post vamos a desarrollar el uso de intercambio de archivos para carga masiva de información.

Saludos,

La hora del Planeta: 8.30PM hora local, donde sea que vivas en el planeta Tierra. Sábado 28 de marzo de 2009.

http://sergiot2.com/blogimages/2009/03Mar/2009earthHour.jpg

Falta un poco más de 8 horas para la Hora del Planeta en Perú (GMT-05:00). En algunos partes del planeta ya iniciaron, pero nosotros todavía estamos a tiempo de prepararnos :d.

A los que aún no se han enterado, pueden visitar la siguiente página: http://www.earthhour.org/home/pe:es-419. Algunos pesimistas podrían decir que un hora de ahorro no va a detener el cambio climático, la idea no es detener el cambio climático apagando todo lo que pueda consumir energía eléctrica durante una hora, la idea es hacer que la humanidad tome conciencia de que si no cuidamos el planeta las cosas se podrán cada vez peores, hay muchos nevados que están despareciendo, en Perú, acá cerquita en Huaraz, dentro de poco quizás solo haya cerros secos.

Link: Reseña peruanaza.

Saludos,

[CodeSnippet] Mostrar un Label en ASP.NET por 3 segundos

Requerimiento: Después de procesar una operación contra la base de datos, se desea mostrar un mensaje de confirmación en un Label, pero que el mismo desaparezca en unos tres segundos, ver pregunta.

Solución: Conociendo el funcionamiento de la infraestructura web, el browser es quien automáticamente pasado los 3 segundos debe ocultar el mensaje mostrado. Dado que la funcionalidad que necesitamos es del lado del cliente, la opción es usar JavaScript. Dentro de los eventos Timing de JavaScript, existe el método setTimeout() que pertenece al DOM Window, este método permite ejecutar una sentencia o función JavaScript, después de un determinado tiempo. Y la propuesta será tener dos funciones, una que muestre el “Label” y que a la vez llame dentro de 3 segundos a otra función que oculta el Label. Y finalmente para integrarlo con nuestro botón de ASP.NET, al finalizar la ejecución del mismo podemos registrar el script del lado cliente, usando el método RegisterStartupScript de la propiedad Page.ClientScript. Nota: no es necesario usar un Label, podemos usar el elemento HTML Div para mostrar el mensaje.

Código ASPX:

   1: <head runat="server">
   2:     <title></title>
   3:     <script type="text/javascript" language="javascript">
   1:  
   2:         function MostrarLabel() {
   3:             setTimeout("OcultarLabel()", 3000);
   4:             var msj = document.getElementById("lblMensaje");
   5:             msj.style.visibility = "visible";
   6:         }
   7:         function OcultarLabel() {
   8:             var msj = document.getElementById("lblMensaje");
   9:             msj.style.visibility = "hidden";
  10:         }

</script>

   4: </head>
   5: <body >
   6:     <form id="form1" runat="server" >
   7:     <div>
   8:         <div id="lblMensaje" style="visibility:hidden;">
   9:           <h3>Mensaje mostrado por tres segundos...</h3> 
  10:           <br />
  11:         </div>                
  12:         <input type="button" value="click aqui" onclick="MostrarLabel()" />
  13:         <asp:Button ID="btnMostrarMensaje" runat="server" Text="Mostrar" 
  14:             onclick="btnMostrarMensaje_Click" />
  15:          <asp:Button ID="btnNada" runat="server" Text="No Muestra nada"  />        
  16:     </div>
  17:     </form>
  18: </body>

Código Evento:

   1: protected void btnMostrarMensaje_Click(object sender, EventArgs e)
   2:   {  
   3:     //codigo de operaciones contra la base de datos
   4:     Page.ClientScript.RegisterStartupScript(
   5:        Page.ClientScript.GetType(), "onLoad", "MostrarLabel();", true);
   6:   }

Navegadores Probados: Todos sobre Windows Vista SP1.

  • Firefox 3.0.6
  • Internet Explorer 7.0.6001
  • Opera 9.52
  • Google Chrome 1.0.154.48
  • Safari 3.1.2

Notas:

Recursos:

P.D.: Cuando tenga este tipo de requerimientos, no inventen marcianadas para hacerlo con ASP.NET 3.5++, puede ser tan simple de hacerlo con JavaScript. Ojo, tampoco se quiere concluir que todo lo vamos hacer con JavaScript, debemos buscar el equilibrio, sin afectar la seguridad y el rendimiento.

Saludos,

Recomendaciones para la Adopcion de AJAX usando ASP.NET AJAX

Simple: “No usarlo”… (no tomarlo literalmente)

http://sergiot2.com/blogimages/2009/02Feb/18_aspnet_ajax_logo.png

Repasando: Como ya hemos comentado, la infraestructura que da soporte a las aplicaciones Web es diferente a una aplicación de escritorio. Si bien esta infraestructura es rica en acceso (acceder desde cualquier parte del mundo con una conexión a Internet), también tiene desventajas y una de ellas son los “viajes” que tienen que hacer al servidor Web. Si bien en el navegador estamos viendo una réplica de la información (en formato html), si queremos refrescar la información o hacer alguna operación, nuestro pedido (request) viaja desde nuestra PC hasta el servidor Web, que puede estar al otro lado del mundo, pero gracias al protocolo HTTP se pueden comunicar. Y cada vez que hacemos un request al servidor, tenemos que esperar que se refresque nuevamente toda la página (algunos navegadores usan Cache para los estilos y diseño) lo que da una apariencia de cargar más rápido. De ahí la siguiente necesidad de las aplicaciones Web, después de quedar la satisfecha la necesidad de que sean dinámicas (tecnologías de servidor, asp, php, jsp, etc), es la necesidad de mejorar la experiencia de usuario de las aplicaciones Web, y que puedan ser semejantes al estilo de una aplicación de escritorio, han habido muchos intentos por establecer la tecnología que permitiría mejorar la experiencia de usuario de una Aplicación Web, todos tenían que ver con el complemento del lado del cliente para lograr esto. Pero en los últimos años, los esfuerzos han estado centrados en AJAX, y en las aplicaciones RIA, considerando a estas últimas como producto: Silverlight y Flash, por que las aplicaciones AJAX también hacen una aplicación RIA.

Frameworks AJAX: Implementar AJAX usando directamente el objeto XMLHttpRequest, puede llevarnos a escribir código más limpio y más óptimo, pero el esfuerzo y tiempo invertido para lograr grandes cosas, puede ser muy alto (dependiendo del escenario). Y es por eso que existen los frameworks AJAX, para todos los gustos, sabores, y colores. Aquí hay una lista de un montón de Frameworks Ajax, también pueden verlos agrupados por lenguaje. Microsoft, también liberó para los desarrolladores .NET (y no .Net) un Framework AJAX llamado ASP.NET AJAX.

ASP.NET AJAX, tiene dos componentes: Microsoft Ajax Library (que podría ser usado con PHP, ver WebCast), y otro componente del lado del servidor llamado ASP.NET AJAX Extensions, y que es netamente para integrarse con el Page Framework de ASP.NET 2.0+ (VS2005/VS2008), pueden ver más detalles de la arquitectura de ASP.NET AJAX en el siguiente artículo. ASP.NET AJAX, puede ser una solución mágica, por que rápidamente podemos tener nuestras aplicaciones Web, usando AJAX con sólo arrastrar el control UpdatePanel, podemos tener implementando AJAX en aplicaciones existentes, ver WebCast. Si tienen un mantenedor con una barra de botones, un GridView para mostrar la lista, y un FormView para las demás operaciones, bastaría colocar los 3 controles dentro de un UpdatePanel cada uno, y mágicamente ya tenemos implementado AJAX dentro de nuestra aplicación.

Problema de la Magia, como todo producto mágico, tiene sus costos por detrás. Aunque ASP.NET AJAX maneja postbacks asíncronos con el servidor Web, la información que viaja entre cliente y servidor no es la más óptima, hombre que la magia tiene su coste. Y esto debido a que si no hacemos una buena administración del ViewState, este estará viajando entre los postbacks asíncronos, revisar este artículo para ver un ejemplo. Además de que ASP.NET AJAX es un framework centrado en el Servidor viaja información+diseño entre postbacks asíncronos, a diferencia de un framework centrado en el cliente, que sólo viaja datos entre cliente y servidor, pero hay que “actualizar el diseño” manualmente usando JavaScript y DOM. Este artículo tiene resultados muy interesantes en cuanto a comparación de frameworks de AJAX para ASP.NET.

Alternativa, Una alternativa dentro de ASP.NET AJAX es usar los PageMethods, para que desde JavaScript podamos llamar a los mismos, o también llamar desde JavaScript a Web Services. Con esto garantizamos la transferencia sólo de información, y el diseño hay que modificarlo con JavaScript. Revisar este ejemplo de JavaScript y PageMethods, y JQuery y PageMethods.

Recomendaciones, se que fue mucho floro para llegar a las recomendaciones, pero fue necesario. Si cociendo la “magia” que hay detrás de ASP.NET AJAX, hemos decidido usarlo, por que la aplicación no requiere un alto rendimiento, sólo estará disponible dentro de nuestra empresa (y no a toda la internet, ósea cantidad de usuarios limitada), o hemos visto que en el prototipo, los resultados son aceptables. Hay algunas recomendaciones básicas para usar ASP.NET AJAX:

  1. No usarlo. No usarlo hasta que la página web este funcionando al 100%. La magia de ASP.NET AJAX, a través del UpdatePanel, permite que luego de que la página este funcionando, arrastramos al control UpdatePanel, colocamos nuestros controles de ASP.NET dentro del UpdatePanel, y nuestra página aspx ya tiene AJAX, con sólo arrastrar un control, en este WebCast, se muestra como a una aplicación Web existente (de otro autor), la implementación de ASP.NET AJAX usando el UpdtePanel fue sencilla y no requirió cambiar el modelo de programación. La recomendación, que motiva a no usar ASP.NET AJAX hasta que la página este funcionando, es debido a que muchas veces suele confundirse los errores, y no se sabe si la página no funciona por que el UpdatePanel tiene un bug, o los otros controles que estamos usando tiene bug, y raras veces se piensa que el código que hemos hecho es el que tiene el bug. Por eso, si nos centramos principalmente en hacer funcionar la página al inicio, el rango de causas de errores disminuirá por que no incluye los que pueda producir el uso de ASP.NET AJAX, lo que hará más fácil identificarlos, y solucionarlos, y esto sobretodo para procesos complejos, que tienen que implementarse. En los proyectos participado o en las consultorías y mentoring que hemos impartido con 3Dev, este era un problema frecuente, se tiende a responsabilizar al UpdatePanel de cualquier error que suceda en la página, y siempre hay que hacerse esta pregunta: –la página funciona correctamente sin el UpdatePanel?, y después de remover el UpdatePanel queda claro cual es el origen del error. Un amigo (Luis B.), en tono jocoso, quería demandar a Bill Gates por que ASP.NET Ajax no funcionaba, después de remover el UpdatePanel ya no dijo nada :D.
  2. El UpdatePanel no es barita mágica. Si bien es tan sencillo agregar AJAX a nuestras aplicaciones Web usando el control UpdatePanel, tampoco se debe hacer un uso indiscriminado del mismo. Por ejemplo, dentro de un formulario Web, sólo agregar a los controles que se van actualizar dentro de un UpdatePanel, en una página de mantenimiento sólo a los controles principales como un control GridView, formView, y al menú, pero no a toda la página, la idea de AJAX es actualizar la página asíncronamente para tener una mejor experiencia del usuario, pero si vamos a actualizar toda la página no tiene sentido. Una forma de evitar tener que usar un control UpdatePanel en todo, es usar AsyncPosBackTrigger en un UpdatePanel, un ejemplo, con esto evitamos colocar todos los controles en UpdatePanels. Recuerden que un UpdatePanel se actualiza, cuando un control dentro del mismo produce un PostBack, entonces se actualiza el UpdatePanel y se produce un PostBack asíncrono, o también se actualiza cuando otro UpdatePanel se actualiza, es decir, que si una página tenemos tres UpdatePanels que no están relacionados, si actualizo uno de ellos automáticamente se actualizan los otros dos. Para solucionar este último problema, se puede actualizar el UpdatePanel manual, es decir programáticamente, un ejemplo, aunque esta un poco simple el último ejemplo un posible escenario es si es que dentro de una página aspx, tengo 3 UpdatePanels, y sólo voy actualizar dos, la forma correcta es asignar a la propiedad UpdateMode el valor de Conditional, así solo se actualizarán cuando se produzca un evento dentro de ellos, o cuando se llame explícitamente al método Update del control UpdatePanel.
  3. Cuidado con el dedo compulsivo. Uno de los detalles de usar AJAX, son que cuando se produce un postback asíncrono el usuario (ni el mismo desarrollador) sabe si se ejecuto o no el evento, y entonces vuelven hacer varios clic en el botón para asegurarse que hicieron clic. Es por eso que es necesario usar indicadores para indicarle al usuario, que su pedido se esta procesando, con ASP.NET AJAX pueden usar el control UpdateProgress, pero mucho mejor si lo hacen centrado y bloquean la pantalla.

AjaxControlToolkit (ACT), un juego de controles (ajaxcontroltoolkit.dll) liberados junto con ASP.NET AJAX, hay algunos controles útiles como el control AutoComplete, y bueno otros que se podrían mejorar. Y al igual que ASP.NET AJAX, hay que tener cuidado con el uso del ACT, evaluarlo en nuestros escenarios. Aquí pueden ver los ejemplos de los controles Online, y en algunos controles se aplican la misma regla que el UpdatePanel, primero verifiquen el funcionamiento básico de su página, antes de usar algunos controles del ACT. Ejemplos del ACT, los pueden descargar de la página del mismo en CodePlex, además de los ejemplos se encuentra el código fuente del ACT. Nota: los ejemplos son los mismo que están online, y todos los controles tienen un ejemplo, lo pendiente es revisar que CSS usa el control que vamos a probar, y eso copiarlo a nuestro sitio Web.

Destacado:

Artículos, Videos, Ejemplos:

Saludos,

Buenas practicas de programacion y tecnicas para liberar recursos, para tener una aplicacion mas rapida ¿?

http://sergiot2.com/blogimages/2009/02Feb/06-Tortuga-Lenta-o-Liebre-Rapida.jpg

¿La aplicación web de Geeks.ms es rápida?

¿Rápida, para quién?. Para el programador?, para el usuario?, o para el jefe de proyectos?. ¿Cuántos segundos debe tomar cargar una aplicación para que sea rápida? –4 segundos, 8 segundos, 15 segundos?

Y las mismas preguntas podemos hacernos, para considerar una aplicación lenta.

Antes de jugar al teléfono malogrado, se debería tener un límite para considerar a una aplicación “lenta”. Si dentro de los requerimientos no funcionales, se dice que ningún formulario debe tomar más de 15 segundos para completar una operación, ya se sabe que si página o formulario toma 20 segundos, se podría decir que es lenta. Entonces, para poder definir si una aplicación es lenta o es rápida, el límite debería estar definido en los requerimientos no funcionales, y si no lo esta (en muchos casos), antes de optimizar se debería especificar cual será el tiempo de referencia a tomar, para considerar a una aplicación rápida o lenta. Así cuando llegue alguna queja del usuario por que quiere una aplicación sea más rápida, se revisa si el formulario esta dentro de los límites, y si aún así el usuario quiere más rápida (nuevos límites) ese es otro precio.

¿Todas los formularios requieren optimización?

Normalmente los procesos de mantenimiento, debería ser los más rápidos (usamos el término rápido como comparación no como medida) a comparación de los procesos de búsquedas, cargas masivas, o exportar información o procesos de fin de mes.

Veamos, si una página de mantenimiento sólo requiere hacer operaciones de consulta (muchos registros), inserción (un registro), actualización (un registro), y eliminación (un registro), no debería tomar más tiempo que otras páginas de procesos más complejos. Y para lograr esto debemos tener algunos detalles en cuenta, que son básicos:

  • Administrar correctamente las conexiones a la base de datos, liberar los recursos después de usarlos. Desde .Net, podemos usar la clausula using, para asegurarnos de liberar los recursos. Revisar esta entrada: Ado.Net y Using.
  • Paginar los resultados desde la base de datos, y no desde el cliente. Hay algunos controles mágicos que ofrecen, paginación, pero a qué costo?. Por ejemplo para paginar en Oracle podemos usar ROWNUM, y en SQL Server podemos usar ROW_NUMBER, obviamente que para lograr una paginación del lado de cliente, involucra que tengamos que pasarle dos parámetros más como el registro inicial (startRowIndex) y la cantidad de resultados (maximumRows), además de que tengamos que hacer otro método y procedure, para “contar”, ya que necesitamos saber cuantas páginas tiene el resultado.

Si seguimos estas dos reglas básicas, los formularios de mantenimiento deben ser los más rápidas de toda nuestra aplicación. Y entonces, páginas o formularios a optimizar son los procesos de búsquedas, operaciones masivas, generación de reportes, entre otros procesos complejos (1).

¿Pero qué pasa, si toda la aplicación esta lenta? Sean de mantenimientos simples o complejos, o procesos, todas demoran mucho a comparación de otra aplicación (una aplicación Web frente a una Windows). Sobre todo en esas migraciones por tendencia o moda de una aplicación Windows a Web, sobretodo si no se tiene muy claro la infraestructura de una aplicación web, el usuario dirá: pero en la aplicación Windows era más rápido, como le explicas que el navegador tiene que hacer un viaje al servidor, o lo que se conoce como postback en asp.net,  para poder ver los resultados. Y la migración de una aplicación se puede vender por dos cosas: por mejoras de procesos, o por que va ser más rápido, entonces nuevamente por que la web mas lenta, se preguntará el usuario. Entonces, si la mayoría de formularios están lentos a comparación de su previa versión, habrá que revisar el código base o código común (2).

¿Juego de Herramientas o técnicas del buen optimizador?

  1. Profiler del motor de base de datos. En el escenario 1, y el escenario 2, es bueno identificar cuales son las operaciones que se están haciendo contra una base de datos, y el tiempo que están tomando estas operaciones, la cantidad de operaciones que se esta haciendo, quizás es redundante el número de operaciones. Imaginen, que están haciendo un búsqueda sobre un catálogo de libros, tenemos varios millones de libros en nuestro catalogo, y tenemos que buscar por título, descripción, contenidos. Para SQL Server nosotros tenemos SQL Profiler. Después de analizar podemos llegar a dos conclusiones, una determina consulta esta tomando un tiempo mayor al esperado, hay que determinar si podemos hacer alguna mejora para incrementar la performance del servidor de datos, también revisar esta presentación: buenas prácticas para mejorar el rendimiento en un servidor SQL Server. Y si el problema, no esta en la consulta, si no en la recurrencia a la información?, en este escenario donde la información mostrada cambia pocas veces (una noticia de un diario, las entradas de un blog) se puede hacer el uso de técnicas de Cache, atención si la aplicación tiene alta transaccionalidad es decir se necesita hacer operaciones con la información más reciente, imaginad hacer ventas de productos que tienen stock 4 (por que así se guardo en la cache) cuando un producto ya no tiene ese stock 4, en este último escenario no es aplicable el uso de Cache.
  2. Profiler de nuestro código. Es una manera de identificar cuales son los cuellos de botella dentro de nuestro código, o para optimizar hasta la última línea de código. [.Net] Carlos Walzer, por ejemplo nos muestra el uso de la herramienta dotTrace 3.0, para analizar el tiempo y la cantidad de cada una de las llamadas dentro de .Net, con la cual podemos llegar a la mejor forma de hacer las cosas, revisar la serie: Cazando mitos en ADO.NET.
  3. Profiler del render del Html (Web). En una aplicación Web, hay otro detalle a tener en cuenta y es el tamaño del html enviado al navegador. Una excelente herramienta para detectar motivas de lentitud en la carga de una aplicación web es usar YSlow, y si están usando asp.net también puede usar la característica Tracing, con la cual podemos identificar los métodos dentro del ciclo de vida de ejecución de una página ASP.NET, además del tiempo de ejecución de los mismos, para saber cual demora más; lo otro que podemos identificar el tamaño de bytes que ocupa el render de todos los controles de la página, así como el ViewState ese monstruito que es bueno pero a la vez es malo que están ocupando. El ViewState sólo debería ser usado cuando es verdaderamente útil, todos los controles por defecto tienen habilitado el ViewState. Por ejemplo si ustedes hacen ver código fuente html de esta página, encontrarán un elemento llamado: __VIEWSTATE, y en este caso de Geeks.ms, y si vamos a un decoder online, veremos que sólo tiene un valor, que es el código de la página, si están desarrollando con ASP.NET, hagan “View in Browser” y vean el tamaño del ViewState, y vean con el decoder que se esta guardando.

Otro detalle a tener es al no liberarse correctamente los recursos y ocupar memoria, “fuga de memoria”. Dentro de Windows existe una herramienta llamada WinDBG, que puede ser usado para identificar fugas de memoria dentro de .Net por ejemplo. Y específicamente para .Net podemos usar el CLR Profiler, como en este escenario: Cómo cazar una fuga de memoria en .Net, también podemos usar .NET Memory Profiler.

Resumiendo

  1. Se debe especificar, el rango para que una aplicación sea considera rápida o lenta.
  2. Los formularios de mantenimiento deberían ser los más rápidos dentro de nuestra aplicación, por que las operaciones son simples, y debemos seguir las reglas básicas, de paginación del lado del servidor de datos y liberación de recursos (conexiones).
  3. Los formularios especiales, necesitan de herramientas especializadas para identificar donde se encuentra el cuello de botella, o los lugares posibles de optimización. Para ello disponemos de Profilers, a nivel del servidor de datos, como también a nivel del código de nuestra aplicación.
  4. Para aplicaciones Web, asegurarse que el render del html sea el adecuado.
  5. Tener cuidado con las fugas de memoria.

P.D.: Espero que esta lista de herramientas, ayuden a mejorar el rendimiento de sus aplicaciones, en algún momento mostrare algunas de ellas en determinados escenarios para ver su utilidad más claramente, quedan en los drafts como constancia.

Oros artículos de interés:

Saludos,

Aplicaciones de Escritorio vs Aplicaciones Web, ¿hay diferencia en el desarrollo?

Esto post nace como respuesta a las siguientes preguntas o dudas:

  • Estoy desarrollando una aplicación Web, en Windows yo usaba el evento KeyPress pero en asp.net, asp, php, jsp, o xsp no se como hacerlo.
  • De una página A envío información a una página B, quiero que al cerrar la página B el foco regrese a la página A. Esta última es clásica en los foros, además de venir con esta nota la final: el código debe estar con C# 2008 y usando mejores prácticas
  • El diseñador de Visual Studio .Net no funciona, arrastre mis controles pero en el navegador se ve todo feo
  • Voy a desarrollar una página, y no se que lenguaje usar JavaScript, C#, JSP, Php, o ASP.Net, ¿con cuál de estos se ve mejor mi página?
  • Quiero pasar variables usando POST en asp.net, y no se como hacerlo
  • ¿Cuáles son los navegadores más usados? Estoy haciendo una web con Php, y no quiero hacer muchas versiones de mi código, sólo para 3 navegadores como máximo
  • Estoy haciendo una Web 2.0, estoy programando con JavaScript y no puedo conectarme a la base de datos
  • -¿Qué estas usando para desarrollar tu Web html o xhtml?, –No uso html, yo estoy usando lo ultimito uso ASP.NET 3.5, dicen que html ya esta desfasado.
  • -¿Y ya aprendiste Html y Javascript para tu proyecto Web?, –No, con Visual Studio .Net ya no se usa eso, sólo arrastras controles y programas como en Windows

Para responder a las preguntas vamos a ver una arquitectura simple de dos aplicaciones una Windows (o de escritorio) y una Web

Aplicación de Escritorio

http://sergiot2.com/blogimages/2009/01Ene/14-Windows.png

En una aplicación de escritorio normalmente no iniciamos sesión por cada aplicación que usemos, sólo se inicia sesión una vez cuando prendemos el sistema operativo, asumiendo que vamos a abrir una aplicación para ver nuestra lista de tareas:

  1. El usuario carga la aplicación.
  2. La aplicación (el código), se conecta a la base de datos y recupera la información del usuario.
  3. La aplicación muestra al usuario la información solicitada.

Aplicación Web

http://sergiot2.com/blogimages/2009/01Ene/14-Web.png

El usuario desde cualquier parte del mundo y desde cualquier dispositivo (PC, laptop, mobile), desea ver donde será el próximo @BeerTwit.

  1. El usuario tiene que ingresar la URL de la página en su navegador (*1). El navegador por detrás se encargará de hacer un request (solicitud) al servidor Web usando el protocolo de comunicación HTTP (*2) (internet), y en este caso usará el método GET, por que sólo quiere obtener información.
  2. El servidor Web recibe el request y envía un response (sólo html) al navegador. Los navegadores no entienden el código ASP, PHP, o JSP, ellos sólo muestran contenido en html (*3), es por eso que todos los servidores Web después de procesar un request devuelven sólo html (que puede incluir Javascript (*4)), el html generado debe ser un formulario en html, para que el usuario pueda enviar su información. Por otro lado si el usuario ha iniciado sesión con anterioridad es posible que su sesión este activa, y no tenga que iniciar sesión nuevamente.
  3. El usuario llena su información, user y password, y hace clic en el famoso botón “Sign in”. El navegador por detrás recolectará esta información, y en este caso que se desea enviar esa información al servidor debe estar usando el método POST. Todos los lenguajes usan POST para enviar información a una página, ya sea ASP.NET, Php, JSP, etc (*5). En el caso especial de ASP.NET cuando están desarrollando por defecto todos los formularios se envían usando POST, pueden hacer “View Source” de una página en el navegador y verán que el formulario html tiene el método POST. Pueden ver también esto usando la herramienta Fiddler. Con GET también se puede enviar variables, pero no es técnicamente enviar información, es mas bien, un obtener información con estos parámetros.
  4. El request llega al servidor Web, y se ejecutará el código de servidor Php, Jsp, o ASP, que se conectará con la base para verificar si existe el usuario y si el password coincide con el enviado por el usuario.
  5. Si el usuario y el password son validos, el código de servidor (login.php, login.jsp, o login.aspx), redireccionará el request a otra página showUpdates.php, la cual se conecta nuevamente a la base de datos para traer todos los updates de los amigos del usuario, después de procesar la página, el servidor envía el response (sólo html) al usuario.
  6. El usuario ve en una página las últimas actualizaciones de sus amigos, y parece que esta semana no habrá @BeerTwit, así que tendrá que inventar alguna excusa para generar uno nuevo.

¿Se nota la diferencia por qué es distinto para programar para Windows, que programar para Web? ¿Todavía no?. Vayamos resumiendo:

*1. El front-end de toda aplicación Web, siempre acabará en un “navegador” y si queremos que se vea bien la mayoría de navegadores debemos desarrollar usando estándares, eso evitará tener que hacer una versión de Html o Css por cada navegador. Ahora también esta de moda tener una versión móvil de las aplicaciones: http://m.elcomercio.com.pe, http://m.hi5.com/, http://m.facebook.com, http://m.twitter.com, http://m.tuWebAqui.com.

*2. El protocolo usado para comunicarse con un servidor web es: “HTTP”, y normalmente usamos HTTP GET o HTTP POST, para cualquier tecnología de servidor. Revisar este Screencast del genial David Salgado: Trabajando con HTTP GET y HTTP POST, acá muestra por ejemplo simular un browser desde .Net haciendo request GET o POST usando la clase HttpWebRequest, aunque también pueden usar la clase WebClient. Por otro lado existen otros métodos de request además del GET o POST, el uso de estos métodos los verán con REST.

*3. Ya hemos mencionado que todo servidor Web devuelve al cliente sólo “HTML”, por eso importante trabajar con estándares para que nuestro diseño se pueda ver bien en todos los navegadores. ¿Por qué el código de mi página (php, jps, asp.net) no se ve bien? Pues posiblemente sea por que no sabemos HTML o no sabemos CSS o el diseño no es nuestro tu tema, si vamos a desarrollar una Web tampoco vamos a centrarnos en aprender html a nivel experto, pero si debemos conocer lo básico sobretodo si nosotros estamos encargados de integrar el diseño con la funcionalidad. ¿Si soy developer como diseño mi página Web?, revisar los comentarios en el siguiente artículo.

*4. Un gran aliado para hacer más dinámica la interacción de nuestra aplicación web con el usuario es usar “Javascript. Recuerden que una aplicación Web, tiene dos ámbitos: cuando esta en el cliente (1), y cuando se hace un request y se va al servidor (2) para procesar el request y generar el response. Entonces, o está en el navegador del usuario o está en el servidor Web, entonces JavaScript es un lenguaje script del lado del cliente, y con el voy poder cambiar elementos dentro de la versión html que este en el cliente. Por ejemplo, puedo con un botón (input: type-button) hacer el llamado a una función en javascript que cambia el color o contenido a un caja de texto (input: type-text), y para hacer esto en la página, no es necesario que la página vaya al servidor, con JavaScript podemos hacer estos cambios del lado del cliente. Si yo hago el cambio de color o contenido de una caja de texto desde un lenguaje de servidor asp o php, la página tendrá que viajar al servidor sólo para cambiar el color. JavaScript da una mejor interacción con el usuario, pero no todo se puede hacer del lado cliente, por que la data, información, el valor, la carnecita, esta en el servidor y hay que viajar para traer esta información. Cada vez que se hace un request al servidor Web (sea GET o POST) se refresca toda la página, lo que da una percepción de lentitud a comparación de Windows, si quieres mejorar esto una de las opciones es usar Ajax. Siempre es bueno conocer lo básico de JavaScript, sobre todo para cuando estemos trabajando con popUps o cualquier interacción del lado del cliente.

*5. Y por último el “lenguaje de servidor, que puede ser Php, Asp, Jsp, y todos los demás. Obviamente si tu labor es desarrollar páginas web con acceso a datos, debes dominar el lenguaje de programación, pero como vimos anteriormente también es útil conocer lo básico de JavaScript, Html, Css, y cuando lo vayas necesitando aprendes más de cada uno de ellos.

Espero que las preguntas propuestas al inicio, hayan quedado resueltas.

P.D.: Y recuerden, programar una aplicación Web no es lo mismo que programar una aplicación de escritorio, pero si va servir nuestros conocimientos de programación. En .Net por ejemplo todas las librerías, a excepción de las propias de Windows, que hayas aprendido programando Windows, te van servir cuando programas en Web, ejemplo: System.IO, System.Xml, System.Data.SqlClient, System.XYZ.

Saludos,

analizando codigo maleado?, tienes que usar NDepend

Entiéndase código maleado, a aquel código que todos los miran pero nadie lo quiere tocar, aquel código en el que actualizas un método, y te das cuenta que tienes que actualizar más del 60% de la aplicación.

El análisis de código, puede ser para entender la arquitectura de una aplicación en particular, para hacer un code review, o para refactorizar proyectos con código maleado.

Para revisar código, y analizar la implementación del mismo podemos usar Reflector, podemos saber que métodos dependen de otro, o que métodos usa, pero no tenemos un mapa del uso de métodos, de clases, de namespaces, etc, hasta pensaba cuando terminé con los drafts del writer hacer un programita para hacer esto. Pero esa es una de las features de NDepend, analizar código.

Vamos a mostrar algunas de las características de NDepend usando mi primera aplicación .Net: Juego de la Vibora (VB.Net) (Jun-2004, 3er año universitario), sin el reto de hacer esa aplicación quizás ahora estuviera escribiendo alrededor de Java. La pantalla de la aplicación es la siguiente, esta tal cual la hice hace 4 años, más detalles sobre la misma en este link.

Gusano .Net

 

Al analizar el ejecutable de esta aplicación usando NDepend obtendremos la siguiente ventana (clic sobre la imagen para ampliar):

NDepend - Gusano.Net

Además genera un reporte Web, con todos los resultados generales. Pero en la interfaz de la herramienta nosotros podemos generar nuevos reportes, y gráficos, por ejemplo podemos ver dependencias no sólo a nivel de Namespaces, si no también de clases y métodos, además de poder hacer consultas dinámicamente a nuestro código. Veamos las ventanas disponibles:

Dependency Graph:

NDepend - Dependency Graph

En este caso estamos viendo el nivel dependencia dentro de la clase Gusano.vb, donde el tamaño de la caja esta determinado por la cantidad de líneas de código.

Dependency Matrix:

http://sergiot2.com/blogimages/2009/01Ene/07-NDepend-Dependency-Matrix.jpg

A diferencia de la anterior ventana de dependencia, en esta ventana vemos la dependencia en números, en la selección, hay 6 métodos de la clase FrmGusano.vb, que están usando 11 miembros del tipo (clase) Gusano.vb.

Metrics:

NDepends - Metrics

Y en esta podemos ver diversas métricas (pre-definidas), de nuestro código. En la selección se esta analizando la métrica Nro de Líneas de código, por método de fondo negro, y las de color azul son el TOP 10, de los métodos con mayor cantidad de líneas de código. Actualmente tiene 82 métricas de código, leer más. Recordar también que ahora VS2008, tiene una herramienta llamada Code Metrics, revisar este artículo del buen amigo, el Bruno: [VS2008] Code Metrics.

CQL Query Edition

http://sergiot2.com/blogimages/2009/01Ene/07-NDepend-CQL-Query.jpg

Y con esta ventanita que se puede hacer de todo, usando: Code Query Language (CQL), que es un lenguaje de consultas contra nuestro código analizado. En la ventana, se puede apreciar las 10 clases con la mayor cantidad de métodos. Otras consultas que podríamos hacer:

  • ¿Qué clases implementan un interface en particular?
    SELECT TYPES WHERE IsClass AND Implements "System.IDisposable"
  • ¿Cuáles son los 10 métodos más complejos, usando la métrica Cyclomatic complexity
    SELECT TOP 10 METHODS ORDER BY CyclomaticComplexity
  • Revisar más opciones de CQL.

Algunos artículos sobre la aplicación de NDepend en algunos escenarios reales, código bien maleado:

También en el blog de Patrick Smacchia, Lead Developer de la herramienta, encontrarán muchas entradas sobre NDepend: Varios artículos de Patrick sobre NDepend. Y la página del producto: http://www.ndepend.com.

Artículos relacionados:

Saludos,

encriptando o cifrando informacion?

http://sergiot2.com/blogimages/2008/12Dic/Criptografia.jpg

La necesidad de encriptar (ocultar a simple vista) información no es necesidad propia en los sistemas de información, su inicio y apogeo fue marcado por las diversas guerras que hubo en la historia, se presume desde las campañas militares de los romanos hasta las últimas guerras mundiales.

¿Qué ha cambiado, en el presente? Pues que ahora contamos con computadores más potentes capaces de poder desencriptar (vamos a usar estos neologismos en la entrada, si prefiere, reemplazar por cifrar/descifrar) la información «oculta», utilizando fuerza bruta por ejemplo. Y desde hace décadas se tratado de mejorar y llevar al proceso de estandarización los algoritmos de encriptación.

Veamos, un ejemplo sencillo usando el método de encriptación CCQSMO cualquier cosa que se me ocurra:

La palabra Geeks.ms:

  1. Obtener el código Ascii: 7110110110711546109115
  2. Le sumamos 10 (clave) a cada código Ascii: 8111111111712556119125
  3. Volvemos a convertir a cadena, y tenemos nuestra cadena encriptada: Qoou}8w}

Obviamente hay algoritmos de encriptación, y hay «algoritmos». Vamos a repasar algunos de estos métodos y sus respectivas codificaciones, pero antes vamos diferenciar algoritmos de encriptación y métodos de cifrado Hash.

¿Se han preguntado porqué cuando se registran en algunos foros, al hacer un «recovery password», no me devuelve el password que he perdido, el sistema devuelve un nuevo password. ¿Por qué? Es que no esta usando un algoritmo de encriptación para ocultar el password, esta usando una función Hash, y es en un sólo sentido, en otras palabras, no se puede recuperar la cadena original a partir del password. ¿Entonces, cómo hace el match?, pues lo que hace no es desencriptar el password cifrado, para compararlo con el input del usuario, lo que hace es volver a cifrar/encriptar el input, y si el input cifrado coincide con el password cifrado que esta en la base de datos, entonces valida exitosamente tus credenciales. Mas detalles: Hash vs Encryption y Hashing vs. Encryption.

Hecho esta aclaraciones vamos a listar los métodos de criptografía, a los cuales podemos encontrar en dos grandes grupos:

1.a) Criptografía simétrica (en):

Estos algoritmos, usan una misma clave para encriptar/desencriptar el mensaje. En .Net tenemos el namespace: System.Security.Cryptography, para las operación de encriptación:

 

 1.b) Criptografía asimétrica (en):

Usa dos claves para el envió de mensajes, una clave pública y una clave privada. El destinatario del mensaje es el que posee estas dos claves, y envía la clave pública al remitente, y sólo con la clave privada (que tiene sólo el destinatario) puede desencriptar el mensaje.

2) Funciones de encriptación hash:

Como comenté al inicio, es encriptación (o cifrado) en un sólo sentido, no se puede recuperar el texto original a parte del texto encriptado. Además de tener la particularidad de generar un texto de un tamaño específico, siendo único cada contenido generado.

 

Ahora que ya vimos, los algoritmos de encriptación y funciones hash. Vayamos con algunos ejemplos, y su aplicabilidad dentro del entorno .Net

a) Encriptando secciones del web.config, con estos artículos queda clarísimo: Cifrado de información en los archivos de configuración de ASP.NET y Encrypting Configuration Information in ASP.NET 2.0 Applications. Podemos usar dos providers: RSA o DPAPI, básicamente DPAPI es más segura por que esta atada a la máquina donde se realiza la encriptación (leer los comentarios de José M.A.). Pero el proveedor DPAPI (DpapiProtectedConfigurationProvider), qué algoritmo usa? Utiliza una API del sistema operativo llamada Windows Data Protection, y es expuesta a través de: Crypt32.dll (Win32).

b) ¿Que algoritmo de encriptación usa el servicio de membership de ASP.NET 2.0+? Si estamos usando el servicio de Membership de ASP.NET 2.0+, dentro del web.config, en el elemento membership, nosotros podemos definir el formato del password a almacenar en la base de datos, y puede ser de tres tipos: Clear, Encrypted, and Hashed. Clear, almacena el password en texto plano (por si me olvidó, o me gusta modificar el password directamente en la base de datos con un Open Table), Hashed para usar una función hash (en un sólo sentido), y Encrypted, para poder encriptar/desencriptar un password. ¿Qué implicancia tiene, usar Hashed o Encrypted?, pues que si estamos usando el control PasswordRecovery, con el formato Hashed no vamos a poder recuperar el password, lo que hará el control es generar un nuevo password, recuerden que Hash es un sólo sentido. ¿Qué algoritmos usa, y donde lo configuro? La configuración se hace en el elemento machineKey, y puedo usar las funciones hash MD5 y SHA1, y los algoritmos de encriptación simétrica 3DES y AES.

P.D.: Esto es el fruto de dos amanecidas hasta las 2:00 a.m., una rápida revisión a los algoritmos de encriptación, y sus respectivas implementaciones en .NET, que lo disfruten!

Saludos,

[Ado.Net] Clase de conexion generica para cualquier motor de base datos, usando .Net Providers

Problema: En internet hay mucha información sobre como trabajar con Ado.Net y SQL, pero cuando tenemos que usar un nuevo proveedor  de base de datos desde .Net, comenzamos a buscar ejemplos específicos sin darnos cuenta, que también podemos usar los ejemplos de Ado.Net y SQL (usar la estructura).

Solución: Exponer una estructura básica de Ado.NET para las diversas operaciones que podemos hacer una fuente de datos, consultar, insertar, actualizar, y eliminar, y que esta estructura puede ser usada con cualquier proveedor disponible en .Net.

En el artículo usaremos las clases: XyzConnection, XyzCommand, XyzDataReader, y un XyzParameter, para presentar las clases base que después pueden ser reemplazadas (en la mayoría de casos) por las siguientes clases de acuerdo a los proveedores:

  1. SQL Server: SqlConnection, SqlCommand, SqlDataReader, y SqlParameter.
  2. SQL Server CE: SqlCeConnection, SqlCeCommand, SqlCeDataReader, y SqlCeParameter.
  3. Oracle (ODP.Net): OracleConnection, OracleCommand, OracleDataReader, y OracleParameter. Hay un proveedor de MS: Microsoft’s .NET for Oracle Provider, pero el Oracle Data Provider for .NET, es el oficial de la gentita de Oracle.
  4. DB2: DB2Connection, DB2Command, DB2DataReader, y DB2Parameter.
  5. MySQL: MySqlConnection, MySqlCommand, MySqlDataReader, y MySqlParameter. Ejemplos: Connector/NET Examples and Usage Guide.
  6. PostgreSQL: NpgsqlConnection, NpgsqlCommand, NpgsqlDataReader, y NpgsqlParameter. Ejemplos: Npgsql 2.0 User Manual.
  7. VistaDB: VistaDBConnection, VistaDBCommand, VistaDBDataReader, y VistaDBParameter.
  8. OleDb: OleDbConnection, OleDbCommand, OleDbDataReader, y OleDbParameter.
  9. Odbc: OdbcConnection, OdbcCommand, OdbcDataReader, y OdbcParameter.
  10. Y así…., se entiende la idea?. Ya no pongo más proveedores, por que no acabo la entrada. No se pierda la saga: OleDb vs Odbc.

En el caso que este disponible un proveedor puntual para una fuente de datos, podemos usar OleDb, y si no esta disponible en está, podemos usar Odbc:

  1. Access. Ejemplo de conexión con OleDb. Ejemplo en código: Using ADO .NET – Access and OleDB Part 2. Más ejemplos.
  2. Excel: Ejemplo de conexión con OleDb. Ejemplos en código: Reading Excel (.xls) Files with ADO.NET, y Reading and Writing Excel Spreadsheets Using ADO.NET C# DbProviderFactory. Más ejemplos.
  3. Text Files (CSV, tab, custom): Ejemplo de conexión con OleDb. Ejemplo en código: Using OleDb to Import Text Files (tab, CSV, custom). Más ejemplos.
  4. Se entiende la idea?

 

Código Ejemplo

Y después de tantos links, vayamos con el código propuesto para hacer operaciones (CRUD) contra una fuente de datos.

En nuestro modelo, para enviar o recuperar información no vamos a usar DataSet ni DataTables, vamos a usar objetos y listas (generics) de objetos:

  1. Las listas de objetos son tipadas. Con dataset: Convert.ToInt32(ds.Tables[0].Rows[0][«SupplierID»]), con un List<Supplier>: lstSuppliers[0].SupplierID, se nota la diferencia no?. El dataset también se puede tipar, pero no viene por defecto.
  2. El rendimiento que se puede lograr con una lista puede ser mejor que con DataSets. Revisar: Anti Prácticas .NET: Lectura de Datos con ADO.NET II.
  3. Si están trabajando con ASP.Net, es soportado por el control ObjetDataSource.
  4. Le tengo cariño a los List<Object>.

P.D.: Ojo con esto no quiero desechar a los Dataset y Datatable, quizás para Winforms se le encuentre más beneficios (traer toda la data y filtrar data en memoria), pero en entornos Web la palabra rendimiento es más necesitada, por eso los filtros deben venir desde la base de datos y no en memoria.

Como vamos a usar Listas (generics) de objetos para pasar entre nuestros métodos/capas, vamos a tener que definir nuestras entidades (capa de Entidades). La definición de nuestro entidad Category (Category.cs):

   1: using System;
   2:  
   3: namespace Northwind.BO
   4: {
   5:  public  class Cateogory
   6:   {
   7:  
   8:    private Int32 categoryIDField;   
   9:    public Int32 CategoryID
  10:    {
  11:      get { return categoryIDField; }
  12:      set { categoryIDField = value; }
  13:    }
  14:  
  15:    private String categoryNameField;
  16:    public String CategoryName
  17:    {
  18:      get { return categoryNameField; }
  19:      set { categoryNameField = value; }
  20:    }
  21:  
  22:    private String descriptionField;
  23:    public String Description
  24:    {
  25:      get { return descriptionField; }
  26:      set { descriptionField = value; }
  27:    }
  28:  
  29:   }
  30: }

Esta clase (entidad) normalmente tiene un atributo por cada columna de la tabla a mapear. En este caso hemos mapeado la tabla Category, de la famosísima Northwind. Nota: Si es una aplicación Web ASP.NET, y va usar el control ObjectDataSource, no se olvide de usar el atributo: DataObjectField. Leer más.

Ahora vamos a implementar la clase de acceso a datos (capa de acceso a datos) XyzCategory. Esta sólo es una clase base, y podemos hacer el uso de patrones, interfaces, o custom, para hacer más genérica esta estructura, y que sea el contrato para cualquier operación con la base de datos. Por hacer más simples los métodos, quedo pendiente el manejo de excepciones, pero cuando intente borrar un registro con dependencias notará su necesidade. No se olvide de revisar el uso de Using (con lección de Unai incluida).

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Configuration;
   4: using System.Data.XyzClient;
   5: using Northwind.BO;
   6:  
   7: namespace Northwind.DA
   8: {
   9:   public class XyzCategory
  10:   {
  11:     private String connectionString;
  12:  
  13:     public XyzCategory(String connectionName)
  14:     {
  15:       connectionString =
  16:         ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
  17:     }
  18:  
  19:     #region getAll , getOne
  20:  
  21:     public List<Cateogory> getAll()
  22:     {   
  23:     }
  24:  
  25:     public Cateogory getOneByID(Int32 catID)
  26:     {      
  27:     }
  28:  
  29:     #endregion
  30:  
  31:     #region Insert, Update, Delete
  32:  
  33:     public Int32 Insert(Cateogory objCat)
  34:     {    
  35:     }
  36:  
  37:     public Boolean Update(Cateogory objCat)
  38:     {    
  39:     }
  40:  
  41:     public Boolean Delete(Int32 categoryID)
  42:     {    
  43:     }
  44:  
  45:     #endregion
  46:   }
  47: }

Vayamos con los métodos específicos, el método getAll vamos a traer la lista de registros. Si están en una aplicación Web la recomendación es traer la información paginada para no traer todos los resultados, y si estamos usando un ObjectDataSource tendríamos que agregar un método Count (será tema de otro post). Nota: para los string que contienen los queries vamos a usar: cadenas verbatim.

   1: public List<Cateogory> getAll()
   2: {
   3:   List<Cateogory> lstSup = new List<Cateogory>();    
   4:  
   5:   //crear conexion
   6:   using (XyzConnection xxxCn = new XyzConnection())
   7:   {
   8:  
   9:     String cmdText = @"SELECT categoryID, categoryName, Description  
  10:                        FROM Categories";
  11:     //crear comando
  12:     using (XyzCommand cmd = new XyzCommand(cmdText, xxxCn))
  13:     {
  14:       //abrir conexion
  15:       cmd.Connection.Open();
  16:  
  17:       //recorrer resultados
  18:       using (XyzDataReader rd = cmd.ExecuteReader())
  19:       {
  20:  
  21:         Cateogory objCat = null;
  22:  
  23:         //recuperar el orden de columnas
  24:         Int32 categoryIDIndex = rd.GetOrdinal("categoryID");
  25:         Int32 categoryNameIndex = rd.GetOrdinal("categoryName");
  26:         Int32 descriptionIndex = rd.GetOrdinal("Description");
  27:  
  28:         Int32 colCount = rd.FieldCount;
  29:         Object[] values = new Object[colCount];
  30:  
  31:         while (rd.Read())
  32:         {
  33:           objCat = new Cateogory();
  34:  
  35:           //obtener todos los valores
  36:           rd.GetValues(values);
  37:  
  38:           objCat.CategoryID = Convert.ToInt32(values[categoryIDIndex]);
  39:           objCat.CategoryName = values[categoryNameIndex].ToString();
  40:           //en el caso de que la columna sea null
  41:           //Null to Int = (exception)
  42:           if ( !(values[descriptionIndex] is DBNull))
  43:           {
  44:             objCat.Description = values[descriptionIndex].ToString();
  45:           }
  46:          
  47:           //agregar objecto a la lista
  48:           lstSup.Add(objCat);
  49:         }
  50:       }
  51:     }
  52:   }
  53:  
  54:   return lstSup;
  55: }

Ahora el método para devolver un registro, si va usar SQL dinámico, es recomendable usar consultas parametrizadas para enviar los ataques SQL-Injection:

   1: public Cateogory getOneByID(Int32 catID)
   2: {
   3:   Cateogory objCat = null;
   4:  
   5:   if (catID > 0)
   6:   {
   7:  
   8:     //connection
   9:     using (XyzConnection xxxCn = new XyzConnection())
  10:     {
  11:  
  12:       String cmdText = @"SELECT categoryID, categoryName, Description
  13:                          FROM Categories 
  14:                          WHERE CategoryID=@categoryID";
  15:       //comando
  16:       using (XyzCommand cmd = new XyzCommand(cmdText, xxxCn))
  17:       {           
  18:         cmd.Connection.Open();
  19:  
  20:         //consulta parametrizada 
  21:         //evita ataques SQL-Injection
  22:         XyzParameter param = new XyzParameter("categoryID", catID);
  23:         cmd.Parameters.Add(param);
  24:  
  25:         using (XyzDataReader rd = cmd.ExecuteReader())
  26:         {
  27:  
  28:           Int32 categoryIDIndex = rd.GetOrdinal("categoryID");
  29:           Int32 categoryNameIndex = rd.GetOrdinal("categoryName");
  30:           Int32 descriptionIndex = rd.GetOrdinal("Description");
  31:  
  32:           Int32 colCount = rd.FieldCount;
  33:           Object[] values = new Object[colCount];
  34:  
  35:           while (rd.Read())
  36:           {
  37:             objCat = new Cateogory();
  38:  
  39:             rd.GetValues(values);
  40:             objCat.CategoryID = Convert.ToInt32(values[categoryIDIndex]);
  41:             objCat.CategoryName = values[categoryNameIndex].ToString();
  42:             if (!(values[descriptionIndex] is DBNull))
  43:             {
  44:               objCat.Description = values[descriptionIndex].ToString();
  45:             }
  46:           }
  47:         }
  48:       }          
  49:     }                
  50:   }
  51:  
  52:   return objCat;
  53: }

Método insertar, notar como pasamos todos los parámetros del registro a través de la entidad. No se pierda la saga @@Identity vs SCOPE_IDENTITY (Only SQL).

   1: public Int32 Insert(Cateogory objCat)
   2: {
   3:   Int32 catID = 0;
   4:  
   5:   using (XyzConnection xxxCn = new XyzConnection())
   6:   {
   7:  
   8:     String cmdText = @"INSERT INTO Categories (categoryName, Description)
   9:                        VALUES (@categoryName, @description) 
  10:                        SELECT SCOPE_IDENTITY() ";
  11:     //comando
  12:     using (XyzCommand cmd = new XyzCommand(cmdText, xxxCn))
  13:     {
  14:       cmd.Connection.Open();
  15:  
  16:       //parametros
  17:       XyzParameter param = 
  18:           new XyzParameter( "categoryID", objCat.CategoryName);
  19:       cmd.Parameters.Add(param);
  20:       param = new XyzParameter("Description", objCat.Description);
  21:       cmd.Parameters.Add(param);
  22:  
  23:       catID = Convert.ToInt32(cmd.ExecuteScalar());
  24:       
  25:     }       
  26:   }     
  27:   return catID;
  28: }

Método Actualizar, si van tener varios tipos de actualización como actualizar registro y actualizar estado, podría crear dos métodos Update con distinto nombre, y cada uno con el query específico y usando sólo las propiedades que necesite:

   1: public Boolean Update(Cateogory objCat)
   2: {
   3:   Boolean exito = false;
   4:  
   5:   using (XyzConnection xxxCn = new XyzConnection())
   6:   {
   7:  
   8:     String cmdText = @"UPDATE  Categories 
   9:                        SET categoryName = @categoryName, 
  10:                            Description =  @description
  11:                        WHERE categoryID = @categoryID ";       
  12:     using (XyzCommand cmd = new XyzCommand(cmdText, xxxCn))
  13:     {
  14:       cmd.Connection.Open();
  15:       
  16:       XyzParameter param =
  17:           new XyzParameter("Description", objCat.Description);
  18:       cmd.Parameters.Add(param);
  19:       param = new XyzParameter("categoryName", objCat.CategoryName);
  20:       cmd.Parameters.Add(param);
  21:       param = new XyzParameter("categoryID", objCat.CategoryID);
  22:       cmd.Parameters.Add(param);
  23:  
  24:       exito = Convert.ToBoolean(cmd.ExecuteNonQuery());
  25:  
  26:     }      
  27:   }     
  28:  
  29:   return exito;
  30: }

Y con el último método, eliminar, para cerrar la entrada. Nota: no se olvide de revisar el tema de manejo de excepciones.

   1: public Boolean Delete(Int32 categoryID)
   2: {
   3:   Boolean exito = false;
   4:  
   5:   using (XyzConnection xxxCn = new XyzConnection())
   6:   {
   7:  
   8:     String cmdText = @"DELETE  Categories                            
   9:                        WHERE categoryID = @categoryID ";      
  10:     using (XyzCommand cmd = new XyzCommand(cmdText, xxxCn))
  11:     {
  12:       cmd.Connection.Open();
  13:      
  14:       XyzParameter param =
  15:           new XyzParameter("categoryID", categoryID);
  16:       cmd.Parameters.Add(param);    
  17:  
  18:       exito = Convert.ToBoolean(cmd.ExecuteNonQuery());
  19:  
  20:     }        
  21:   }    
  22:  
  23:   return exito;
  24: }

P.D.: Preguntas (con respecto a la estructura), sugerencias, bugs, en los comentarios por favor :D. A medida del tiempo, y bajo demanda trataré de enviar ejemplos específicos para un determinado proveedor .Net.

P.D.2.: Si tiene preguntas técnicas con respecto algún código en alguno de estos providers, les recomendaría visitar algunos de los foros de estos productos (.Net Providers), quizás en algún hilo del foro ya se encuentre la solución.

Saludos,

Reto: Descifra el codigo

Para seguir con la saga: «Retos on Geeks.ms«

Quizás algunos ya hayan visto este código u otros lo descifren muy rápido, así que abstenerse en los comentarios para dar chance a los demás. Es un código en JavaScript, y la idea es tratar de saber que genera el document.write, sólo viendo el código, sin compilar o depurar usando algún editor.

   1: e = '0x00' + '19';
   2: str1 = "%A2%FA%F1%EC%86%EB%EA%E1%F2%FD%A5%B8%EC%F1%EB%F1%F8%F1%F2%F1%EA%E1" +
   3:        "%A0%FE%F1%FA%FA%FD%F4%B8%A4%A2%F1%FC%E8%F9%F5%FD%86%EB%E8%FB%A5%B8" +
   4:        "%FE%EA%EA%F6%A0%B7%B7%EA%F1%F6%F7%FB%F4%EA%B4%FB%F7%F5%B7%F2%FA%B7" +
   5:        "%F5%FD%F4%EA%B7%B8%86%EF%F1%FA%EA%FE%A5%A9%86%FE%FD%F1%FF%FE%EA%A5" + 
   6:        "%A9%A4%A2%B7%F1%FC%E8%F9%F5%FD%A4%A2%B7%FA%F1%EC%A4";
   7: str = tmp = '';
   8: for (i = 0; i < str1.length; i += 3) {
   9:     tmp = unescape(str1.slice(i, i + 3));
  10:     str = str + String.fromCharCode((tmp.charCodeAt(0) ^ e) - 127);
  11: }
  12: document.write(str);

En la noche, o quizás mañana voy a tratar de enviar de que trata este código.

P.D.: Para este reto, el premio es la satisfacción de ver lo que genera el código :D.

Saludos,