MSDN Blogs
  • WarNov Developer Evangelist

    Introducción a Generic Handlers en ASP.NET

    • 2 Comments

    Un Generic Handler (GH) es una clase de objeto .NET que puede procesar http requests, sin necesidad de estar dentro del scope de una página aspx (que está dirigida a presentar salidas de tipo HTML clásico). Un ejemplo de GH es el HTTP Handler. Como es bien sabido un http Handler se puede asociar a cualquier extensión de archivo (de acuerdo a lo permitido por el IIS). Los GH sin embargo, solo se pueden asociar a la extensión ASHX que está directamente soportada por los proyectos web en visual Studio 2005 y posteriores. Así que los GH en .NET se asocian a archivos con extensión ASHX.

    Todos los Handlers implementan System.Web.IHttpHandler. Además, en IIS 7 se puede alojar cualquier Handler directamente.


    El hecho que el GH pueda correr fuera del entorno de una página y aparte procesar HTTPRequests, lo hace una herramienta perfecta para ofrecer servicios similares a los que ofrecería un Web Service. De esta manera, es un muy buen candidato para reemplazarlos, cuando no se pueden implementar ya sea por requerimientos del negocio o requerimientos no funcionales.

    Por qué puede no ser deseado un WebService?

    Según la arquitectura y requerimientos de algunos clientes, es mejor recibir resultados a través de HTTPRequest "simple", debido a que por ejemplo el llamado se hace desde una plataforma distinta a .NET desde la cual se hace bastante complejo crear un llamado a un WebService, tal vez porque la herramienta no puede manejar todos los tipos estándar en los WebServices (como sucede por ejemplo con PHP antiguo).

    Entonces por qué no hacer una página Web Normal que responda a los llamados?

    Si se crea una página aspx que responde a las peticiones se incurre en adicionales encabezados y todo el overhead adicional que genera la creación de una página completa (ciclo de vida, viewstate, etc), cuando en realidad sólo se desea obtener una simple respuesta (una imágen un xml, etc).

    Entonces para ganar performance y facilidad de administración en este tipo de funciones, es posible crear un Generic Handler sin dejar de atender al requerimiento de que la comunicación permanezca sencilla.

    Entre los métodos obligatorios al estarse implementando IHttpHandler está ProcessRequest que es el que ejecuta el proceso requerido y por ende al fnal de su alcance habrá de tener un llamado a context.Response.Write o similar, que devuelva una respuesta http. Esta respuesta puede ser html, txt plano, imágenes, xml, etc.

    Uso Avanzado 

    Suponga le siguiente escenario: Existe un objeto en memoria que se desea presentar al usuario como una página html.

    Opciones:

    1. Serializar el objeto a XML, leer el XML y pasarlo a un XSLT que crea el HTML, y grabarlo en un archivo que luego es presentado en un IFrame. Como es obvio, el overhead de crear y borrar estos archivos físicos generados es absolutamente inaceptable.
    2. Otro enfoque es incluir en la página un control XML que muestre el objeto serializado y en el cual luego de hacer la transformación se vea el HTML como tal. Es una alternativa muy aceptable que a primera vista no tiene ninguna desventaja, excepto el mismo overhead y tamaño que implica una página ASP.NET.
    3. Generic Handler: Se obtiene un control más directo sin el overhead que implica agregar un control XML a una página que además tendrá otros elementos que sumaran innecesariamente peso al resultado.

    Cómo se Logra?

    Al crear un GH, éste puede ser llamado como cualquier otra página aspx. (Por ejemplo desde un browser) Además también pueden aceptar parámetros: http://warnov.com/miGH.ashx?param=valor;otroparam=otrovalor a través de su URL. Para incluir un GH en su aplicación Web, solo agreguelo como un nuevo item en el proyecto en Visual Studio.

    En el caso especial de querer mostrar un objeto serializado en XML y transformado a través de XSLT es bastante sencillo: Solo se tiene que incluir en el XML la directiva de transformación XSLT y el archivo XSLT se ha de encontrar en la ruta que allí se especifica.

    Conclusión:
    Como se observa, son muchas la aplicaciones que tienen estos objetos y es considerable la ganancia que se obtiene con su uso, aunque en general pasan muy desapercibidos.

  • WarNov Developer Evangelist

    Carga Dinámica de CSS en ASP.NET

    • 2 Comments

    Los descubrimientos descritos a continuación, surgieron de mi necesidad de cargar CSS dinámicamente sin estar creando numerosos temas dentro de una aplicación WEB ASP.NET. Esto es, separar la administración de CSS de los temas. Así un mismo tema podrá tener varios CSS a petición.

    En primera instancia: Toda página que referencie un tema, SIEMPRE cargará todos los CSS incluidos en el mismo, independientemente de que en realidad los necesite, y del nivel de anidamiento en el que se encuentren ubicados. Poco eficiente no es así?

    Como se sabe, los CSS finalmente son Links referenciados en el HEAD de la página que está referenciándolos. Entonces es cuestión de escribir dinámicamente allí la ruta del CSS que se desea cargar y listo.

    Lo anterior se logra agregando un ASP.NET literal control dentro del HEAD, y en el load de la página ajustarlo con el valor que se desea.

    Y listo!!!

    A pesar de que existan varios CSS en la misma ruta de aquel que está siendo referenciado, solo el referenciado se descarga.

    Ventajas?

    • Tener organizados varios CSS y no solo uno gigantesco con todo.
    • En cuanto a ancho de banda, si los CSS se dejan dentro de temas, por más separados que estén si son cargados por medio de referencia al tema desde la página, siempre bajan todos la primera vez que se llamen (luego quedan en el caché y no vuelven a descargarse si no se borra el caché o si no cambian en el server).

    Conclusión:
    Si se desea optimizar el tiempo de descarga, entonces es mejor no usar Themes para cargar los estilos, sino que estos se carguen independientemente usando el modelo de HEAD descrito anteriormente.

    Ejemplo:

    Dado que me han pedido mucho un ejemplo en código aquí va:

    Aspx

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <asp:Literal ID="Literal1" runat="server"></asp:Literal>
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="Este es un ejemplo de texto"></asp:Label>
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        </div>
        </form>
    </body>
    </html>
    

     

    Codebehind

    using System;
    
    namespace WebApplication1
    {
        public partial class WebForm1 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                Literal1.Text = "<link href='Styles/Site.css' rel='stylesheet' type='text/css' />";
            }
        }
    }
    

     



  • WarNov Developer Evangelist

    Problemas con el Connection Pool de ADO.NET

    • 0 Comments
    Cuando se crea una conexión SQL en ASP.NET, por defecto siempre irá al POOL de conexiones administrado por el framework. Es así como ni al cerrarla ni haciéndole dispose, esa conexión realmente se cierra en el SQL Server como tal. El pool de conexiones existe para mejorar en general el rendimiento de las aplicaciones, dado que el hecho de abrir una conexión es bastante costoso. Así que aunque lógicamente la conexión está ConnectionString es requerida, se sirve una de las ya existentes en el pool de una manera más rápida que creandola desde 0 (from the scratch).

    Si no se desea este comportamiento, basta con incluir en la conexión o en el WebConfig POOLING=FALSE

    El pool para un ConnectionString en particular se puede configurar con el número máximo y mínimo de conexiones. Jugar con estos valores puede mejorar o empeorar el rendimiento de la aplicación. El valor por defecto es de 100.

    Existe un error bastante grotesco que puede asustar mucho si no se entiende de connection pools:

    A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

    Ocurre por ejemplo si en el pool no hay conexiones disponibles, debido a que han sido terminadas por un ente distinto a la aplicación (alquien desconectó el cable de red, apagaron el server, le hicieron kill a las conexiones, etc.)

    No ocurre porque la operación esté tardando demasiado. Y el que ocurran excepciones por éste último motivo no se arregla aumentando el timeout de la conexión. El timeout de la conexión se refiere al tiempo de espera para logran conexión con el server de db, antes de que una excepción sea lanzada.

    El tiempo de timeout por defecto es de 15 segundos. Y en el connectionstring está medido siempre en segundos. Siempre ha tener valores positivos o 0. De lo contrario una excepción surge. Si es 0, significa que nunca se lanzará excepción por incapacidad de alcanzar al server. Esto no es buena idea, porque el sistema se puede volver irresponsivo, y no habría indicios de por qué sucede esto.

    Para que los pool funcionen correctamente, debe existir un manejo responsable de las conexiones. Cómo se manejan responsablemente? Cerrándolas cada vez que no se vayan a requerir más.

    SqlConnection conn = new SqlConnection(myConnectionString);
    try
    {
      conn.Open();
      doSomething(conn);
    }
    finally
    {
      conn.Close();
    }


    Como se vé si hay un fallo, igual se cierra la conexión.

    Teniendo en cuenta: http://www.15seconds.com/issue/040830.htm

    "Close and Dispose methods of Connection object are equivalent. Neither one gives you any specific advantages over the other. "

    Por tanto se puede usar también de una forma más elegante y ostentosa:
     

    using (SqlConnection conn = new SqlConnection(myConnectionString))
    {
      conn.Open();
      doSomething(conn);
    }


    El using en este contexto libera todos recursos declarados, por medio de Dispose.

  • WarNov Developer Evangelist

    Trasmitiendo las variables de aplicación entre capas en una solución .NET

    • 0 Comments
    (Y haciéndolas dinámicas)

    Sea el escenario de una típica aplicación 3-tier para un sistema de información. Hay una capa de presentación, una de negocios y la de datos. En la capa de datos según lineamientos plenamente aceptados, tenemos las cadenas de conexión a las bases de datos que se usarán. Si la aplicación se desarrolla con el Framework 2.0, es normal que las capas de datos y negocio, queden representadas por DLLs que luego son consumidas por una aplicación Windows o web, por ejemplo. Entonces cada cliente se comunica con sus capas servidoras que tienen la conexión a base de datos y saben en dónde están los datos para operar.

    Hasta ahí no hay ningún problema. Cuando la aplicación ya está lista para producción, generalmente se usará una base de datos distinta a la usada en desarrollo y quizá en pruebas.
    Este cambio, gracias a la arquitectura del framework 2.0 en adelante, solo implicaría cambiar el archivo de configuración (App.config) de la DLL de capa de datos. Se abre con un editor de texto, y se edita el XML con la nueva cadena de conexión, y ya está. Todos los clientes quedan conectados a la nueva fuente. Pero qué sucede si se crea una aplicación de capas, que no necesariamente tiene la misma conexión de base de datos para todos los clientes? Cómo lograr que cada cliente genere una cadena de conexión dinámica que se pueda cambiar a discreción permitiendo que la aplicación funcione correctamente?

    En el framework 2.0 las cadenas de conexión son tratadas como variables de alcance de aplicación. El otro tipo de alcance es de usuario. Cuando la variable es de alcance de usuario, esa misma, puede ser modificada en tiempo de ejecución. Entonces sería fácil crear métodos para que los clientes de presentación de alguna manera transmitieran los nuevos valores de las cadenas de conexión a las otras capas. No obstante, como mencioné anteriormente, las cadenas de conexión son de alcance "aplicación" y estas variables no se pueden modificar en tiempo de ejecución. Así que para un cliente es imposible modificarlas transmitiendo nuevos valores mientras está corriendo. Así que el método de crear código que transmita los cambios requeridos, no es factible. La solución, aunque es trivial, no es intuitiva y Visual Studio no provee una manera directa para lograrla. Para encontrarla y entender de qué se trata, suponga que llamamos a la cadena de conexión strCon1. Entonces, queda guardada dentro de los settings de la DLL de datos como strCon1 y tiene determinados valores de conexión.

    Además permitiría cambiar la cadena de conexión dinámicamente, antes de iniciar la ejecución de la aplicación (recordemos que ésta es una variable de aplicación). Al distribuir la aplicación, se puede hacer con o sin el archivo de configuración de la aplicación. Si se distribuye sin este, cuál será entonces la cadena de conexión a usarse? Se usaría la última presente al compilar la librería (Esto gracias a la compilación del archivo de propiedades en la clase Settings.settings).

    Como es conocido, cada capa en el framework, vendría representada por un assembly (DLL) por separado. Es decir, cada capa es un proyecto dentro de la solución y cada proyecto de estos, tiene sus propias propiedades y variables de usuario y aplicación. Como ya se mencionó estas variables van en archivos App.config. Al compilar la solución, dentro de cada carpeta de salida de los proyectos queda un archivo App.config para las dallas, y un archivo miaplicacion.exe.config para los ejecutables en el caso de aplicaciones Windows o web.config en el caso de web services o aplicaciones web ( en estos últimos dos casos, el archivo queda en el root del sitio web).

    Lo que uno como desarrollador distribuiría, sería únicamente los compilados y salidas de los proyectos componentes de la solución. Entonces irían en nuestro ejemplo dos DLL (una de datos, la otra de negocio) y el ejecutable. Además irían los archivos de configuración, que en el caso de las DLL se llamarían igual.

    Pero si se llaman igual, cómo se soluciona este problema? Fácil; basta con combinar los archivos de configuración en uno solo con el mismo nombre y listo. Pero es fundamental que los nombres de las variables (por ejemplo de cadenas de conexión) permanezcan invariables.

    En mi búsqueda de esta solución, una de las cosas que intenté fue agregar una variable de aplicación a la capa de presentación, que tuviera el mismo nombre de conexión y los mismos parámetros que la definida en la capa de datos usando la interfaz de Visual Studio. De esta manera se produciría un miaplicacion.exe.config, con la cadena de conexión que usa la capa de datos y así cada vez que yo cambiase este archivo y reiniciase la aplicación, el sistema tomaría los cambios y funcionaría de acuerdo a ellos.
    Al ver con más detalle el resultado, descubrí que el nombre de la variable no había quedado exactamente igual que el usado por la capa de datos. Y en la práctica, este hecho no es muy fácil de identificar.

    Así que dado que uno puede estar tentado a agregar el setting usando la interfaz de Visual Studio, puede incurrir en este error si no se fija lo suficientemente bien. Lo mejor, es no agregar el setting de esta manera. Sino agregar a mano (o editar a mano si ya existe), un archivo App.config y escribir el setting exactamente como se usó en la capa de datos.Cuando así lo hice, con felicidad observé como finalmente los cambios en el archivo XML se veían reflejados en la aplicación, cuando esta empezaba a correr. Esto me dio la flexibilidad requerida para configurar cada cliente con una fuente de datos distinta a la usada en el desarrollo de la aplicación.

    Conclusión: Para propagar las variables de configuración desde las capas más exteriores a las más interiores dentro de un sistema n-tier usando framework 2.0 en adelante, basta con escribirlas todas en el archivo de configuración de la capa más externa, de manera que sean absolutamente idénticas a las usadas en las capas internas. Y no es posible hacer esto, solo con la ayuda de la interfaz gráfica de Visual Studio, pues se requiere editar el archivo manualmente y luego incluirlo en el deployment de la aplicación.


  • WarNov Developer Evangelist

    Enfrentándose al StackOverflowException

    • 0 Comments
    Más de una semana sin solución. Buscaron en internet a ver... nada.
    Los StackOverFlow Exception no se pueden capturar con un try catch. Ni lo intenten. Cuando sucede la aplicación está más muerta que al cerrarla.
    Finalmente, me preguntaron....
    "Eso es que tienen una función recursiva con el punto de parada mal diseñado" les dije.
    Pero no había tal.
    Entonces me puse a mirar...
    En la primera ocasión no vi nada anormal en realidad. Solo un par de cosas para optimizar el código. Pero nada como para decir que el misterioso snack dejara de aparecer.
    Una y otra vez se repetía. Y lo peor, es que era un proceso bastante largo, que siempre fallaba luego de la primera horta. Así que hacer debug era un infierno total.
    En la segunda ocasión que me senté a mirarle el código, tampoco vi nada raro; se me ocurrió que depronto había mucha memoria desperdiciada... pero nótenlo: eso nunca tiene que ver con el stack. Snack es una cosa y Stack es otra y Memoria no tiene que ver con ellos. El Stack almacena el listado de funciones que se han ejecutado. Y tiene un tamaño entre 500 y 1000. Así que si llamamos más de ese número, el stack secillamente se llena y la aplicación colapsa.

    Teniendo esto muy presente, decidí volver a chequear el código una tercera vez...
    y oh sorpresa cuando al fin encontré lo que estaba pasando!!!!

    Había un método que al final del mismo, tenía un disparador de evento. Otra clase capturaba ese evento y en respuesta lanzaba la ejecución de otro proceso distinto que antes de terminar volvía a lanzar ese evento y así sucesivamente. Todo esto siempre se ejecutaba con el mismo thread. Así que cada vez, el método se quedaba esperando a que se ejecutara el siguiente. Por esto el stack comenzaba a llenarse hasta colapsar, porque las funciones no terminaban, pero si se llamaba a otras.

    Es algo para nada obvio. Pero al fin por pura intuición se descubrió. Lo ridículo del asunto, era el mensaje que representaba el evento disparado: "Terminé" Entonces otra clase leía que había terminado y ponía a correr otro proceso. Que sentido tiene eso? Era muy difícil programar a la clase externa que corriera un proceso y luego otro y otro y ya? No lo creo. Sencillamente a algunos diseños les falta ingeniería de verdad.
  • WarNov Developer Evangelist

    Don JSon

    • 0 Comments
    Algunas aplicaciones web requieren AJAX y requieren que su tamaño de página ha de mantenerse bajo límites estrictos. Entonces no es posible usar las librerías de AJAX .NET dado el considerable peso que le agregan a la página, sino usar directamente el objeto XmlHTTPRequest. Adicionalmente es necesario considerar el peso impuesto por los datos que se transfieren desde el server al cliente luego de usar AJAX. En primera instancia uno podría pensar en XML. Pero como se sabe, los archivos se hacen muy grandes con información que finalmente no es la relevante, así que se genera más peso para las páginas. Por este motivo, actualmente se está difundiendo rápidamente el uso de JSON.

    JSON es un sobconjunto del lenguaje JavaScript, que permite representar objetos a través del paradigma llave-valor. En síntesis es como un "fatless" XML, que es mucho más liviano. Y que además tiene la gran ventaja que puede ser interpretado directamente por JavaScript, de manera que tanto el peso de la página como la ejecución se mejorar sustancialmente, ya que no hay que usar librerías para manejo de XML en JavaScript ni hacer tediosos recorridos a través del texto.

    Para JSON hay librerías disponibles en casi todos los lenguajes, incluido C#. De esta manera, cualquier objeto puede ser traducido a de C# a texto JSON en el server, luego transferido al cliente usando Request.Write después de un llamado AJAX, e interpretado inmediatamente por el browser, sin mayor overhead.

    Desde C# 3.0 muchas de estas características están siendo implementadas de forma nativa y ofrecen beneficios incalculables a la hora de desarrollar, por lo que es recomendable desde ya comenzar a usar estos elementos que han existido desde hace mucho tiempo, pero que solo ahora con el auge de “la interpretación – AJAX, Silverlight, etc- han entrado de lleno en el mundo Microsoft.


    El sitio oficial es
    http://www.json.org
    Pero para no devanarse los sesos y entender rapidito el asunto está: http://www.secretgeek.net/json_3mins.asp; en tres minutos sabrán qué es.
  • WarNov Developer Evangelist

    Error en WebService: &quot;The thread have been aborted&quot;

    • 0 Comments
    El webservice protagonista de este post es uno basado en WSDL; así que no aplica para WCF. Fue creado y usado para lo que no debería ser. Una funcionalidad de una aplicación web administradora de contenidos. Como esa era muy compleja para modificarla, entonces la dejaron intacta, solo que le adicionaron el web service, para que la aplicación propia pudiese usar el dichoso administrador de contenidos.

    En teoría funcionaba bien. Pero ante cargas significativas: "The thread have been aborted". Y nadie sabía qué era. Entonces me llamaron a ver que era. Y lo primero que observé, es que el pobre webservice exponía unas operaciones que operaban sobre la base de datos. Y en general eran operaciones costosas. Pero lo peor, es que siempre el webservice tenía que quedarse esperando la respuesta del servidor de DB.

    "Eso es el timeout del webservice" dije.
    "Si, pero ya le pusimos hasta 5000 horas y nada!!"
    Ouch!!!

    Entonces tratemos de optimizar las operaciones de la DB.
    Le pasé el profiler, el DBEngine Tunning Advisor, implementé y borré índices y en efecto. La vaina mejoró.
    Operaciones de 9 minutos pasaron a 3 y en otros casos operaciones de 3 min pasaron a 1 seg (y eso porque el reporte no mostraba menos de 1 seg)

    Pero llegamos al punto en que por más optimización que hicimos, el error seguía pasando y el thread seguía siendo abortado.

    El httpruntime es un parámetro de configuración en el webconfig y jugar con sus valores puede ser catastrófico o genial. (En este punto cuando he nombreado web.config obvio que sabrán que estoy hablando de asp.net. especficamente del 2.0).

    Señores, se los presento aquí.

    Allí encontramos como atributo a executionTimeOut y fue el que le pusieron como en 5000 y nada. Por qué?
    Uno diría que aquí es donde le puede decir al webservice que espere más antes de "morirse". En efecto así es. Lo que pasa es que con el framework 2.0 vino nuevo otro atributo: shutdownTimeout. El primer atributo aplica sobre la aplicación como tal. Pero el segundo aplica sobre el worker process. Así que si está muy bajo para lo que uno quiere, el worker process es "bajado" por ASP.net cuando el tiempo expira y adivinen que pasa "The thread has been aborted".

    Lo pusieron en 1000 y por fin pudieron hacer su prueba completa!!!

    Concluyendo: Para evitarse problemas, no ponga a los webservices a esperar respuestas a trabajos completos. Esto margina el rendimiento de la red, y en general de todos los recursos del sistema. Use mecanismos asincrónicos.

    Si ya la embarró y no hay tiempo para cambios o definitivamente la terquedad o condiciones del negocio no permiten más, acuda al httpruntime y sus dos timeouts; esto puede apagar el incendio.
  • WarNov Developer Evangelist

    Google ofrece IE8

    • 0 Comments

     

    Buscando un link para descargar el Internet Explorer 8 en su versión RTM, me encontré que Google desde uno de sus servidores, estaba ofreciendo descargar el IE8.

    Sí! Un link para descargar IE8 desde Google!

    Muchos dirán: “Qué es esto de por Dios” o “WTF”

    El “valor agregado” que da Google (o que obtiene?) al ofrecer IE8, es que lo ofrece optimizado para trabajar con Google:

    1. Home: Google personalizable (igoogle)
    2. Motor de búsqueda predeterminado es Google
    3. Aceleradores para blogs, email y demás, están ajustados para trabajar con sus productos
      a. Blogspot
      b. Google Maps
      c. Gmail
    4. La barra de Google viene preinstalada

    Para mí esto significa:

    1. A Google le gustó IE8: No van a ofrecer algo en contra de su imagen general (Además tienen su propio Browser!)
    2. Las islas tecnológicas son totalmente inviables
    3. Los buenos productos giran alrededor de sus clientes y no de sus creadores

    Hoy en día los modelos de producto abierto están a la orden. El mismo IE8 permite usar cualquier buscador (Kumo, Google, tú mismo podrías crear el buscador de tu predilección en minutos). Los aceleradores permiten escoger el operador de tu predilección para las acciones disponibles, los WebSlices se basan en estándares completamente abiertos…

    Y no solo pasa con el Browser. Silverlight es el ejemplo cumbre de la apertura que están teniendo tecnologías que otrora estaban encerradas dentro de una sola corporación. Un usuario con Firefox desde Unix podría bien hacer un request a un servidor Apache que interpreta un PHP que escribe XAML (la aplicación Silverlight como tal) con inyección de datos desde MySQL, para ver en una interfaz tridimensional con audio y video los mejores momentos de la última válida Nascar (el ejemplo va en concordancia con el amigo que me inspiró este post) más las estadísticas de la carrera, en una espectacular aplicación Silverlight con tecnología Microsoft.

    Un pequeño apunte aquí: Han notado por ejemplo que los sitios principales de las nuevas tecnologías Microsoft ya no son .com sino .net?

    Ya es muy conocido hoy en día que la diferencia que puede marcar un producto contra su competencia, es la capacidad de ofrecer valor agregado a sus usuarios.

    Y en tecnología, con la gran cantidad de opciones que hay, este valor agregado se ofrece mediante:

    1. La capacidad de integración, para que aquellos acostumbrados a un producto puedan comenzar a usar otro nuevo sin tener que olvidarse de lo que ya saben; de lo que les gusta; de lo que les da dinero.
    2. La capacidad de aceptar los errores, aprender de ellos e implementar soluciones que muchas veces resultan mejores que las ofrecidas por la competencia que anteriormente usaba estos defectos como factores diferenciadores y definitivos.

    IE8 para mí, cumple perfectamente con estas dos premisas sin las cuales, un producto bien puede estar despidiéndose de su market share. Hoy en día me siento seguro hablando de él sin temor a que saquen la innumerable lista negra de otros tiempos.

    Más información en inglés y descarga, desde aquí

  • WarNov Developer Evangelist

    Alternativas para evitar abuso de los portales

    • 0 Comments
    Uno de los principales riesgos en la operación de nuestros portales es su posible abuso por parte de terceros que con el fin de hacerse a la base de datos que los alimentan, están en capacidad de ejecutar todas las consultas que a bien tengan, tanto manual como automáticamente. En este artículo me estaré enfocando en ambientes sin manejo de sesión y autorización que son los más vulnerables a este tipo de anomalías.

    Los portales son muy vulnerables a estos abusos (que no se pueden catalogar realmente como “ataques”) dado que la naturaleza del negocio implica que todas las consultas estén abiertas a todos los públicos y no con menos importancia, a los motores de búsqueda; de manera que no existen mecanismos de autenticación que impidan por ejemplo el acceso al sitio por medio de robots o programas que extraen automáticamente el contenido de nuestros sitios; además existen efectos colaterales como disminución del ancho de banda y de velocidad de proceso en los sitios.
    Existen básicamente dos tipos de acciones que podrían ayudar a mitigar este riesgo. El primer tipo comprende las acciones ejecutadas a nivel de la infraestructura de la aplicación. El segundo tipo consiste en las acciones ejecutadas a nivel de desarrollos adicionales en la aplicación como tal.

    Infraestructura
    Existen servidores de seguridad que reciben todas las peticiones de los clientes antes de que estas lleguen a la aplicación como tal. Esta herramientas se instalan al frente de los servidores web. Y ayudan a través de los siguientes mecanismos:

    Cookies
    Las cookies estarían almacenando la cantidad de requests que está haciendo cada cliente en una unidad de tiempo dada. Esto requiere sin embargo que se exija a todos los clientes el uso de cookies; hay que tener en cuenta sin embargo, que existen muchos usuarios que desactivan estas cookies en sus browsers.

    Javascript
    El uso de javascript permite generar rutinas que los robots no podrían seguir, de manera que el acceso quedaría restringido a estos entes automatizados. La gran contra que tiene este enfoque, es que puede requerir procesos de considerable costo en el servidor. Además que se le estaría restringiendo el uso también a motores de búsqueda como google que usan robots para obtener información de los sitios.


    Aplicación
    A nivel de aplicación el conjunto de acciones posibles es más diverso. Se trata de rutinas destinadas a detectar accesos irregulares a la aplicación. Estas pueden ser provistas como productos terminados ya hechas por terceros, o como desarrollos nuevos dentro de la aplicación.

    Delay
    Existen herramientas como ISTools de Peter Blum, que basadas en un patrón de IP (esto puede ser contraproducente en el caso de que las ips reales estén siendo reemplazadas por las ips de los ISP) detectan los accesos irregulares y generan retardos en las respuestas, advertencias y finalmente denegación del servicio a los supuestos atacantes. Un caso favorable es que en algunas ocasiones los ISP mantienen la ip de sus clientes y la reenvían como una variable HTTP que puede ser consultada. Pero esto no ocurre siempre.

    Javascript y Cookies
    Ambos mecanismos funcionan con desarrollos de productos de igual forma a la que fue descrita en el apartado de infraestructura.

    Listado de Robots
    Herramientas de terceros permiten consultar un IP dada y verificar si ha sido tildada como un robot para en ese caso tomar acciones al respecto.

    Cómo obtener la solución al problema
    Para generar una solución se han de tener en cuenta los siguientes puntos:
    1. Hoy en día no hay una solución ad-hoc que abarque todo el problema sobretodo sin efectos colaterales.
    2. Para generar una solución es muy necesario comenzar por definir unas políticas de detección de abuso que permitan establecer los parámetros para las herramientas que se usaran/construirán
    3. Los mayores problemas se presentan cuando no es posible obligar la autenticación en los portales luego no hay manejo de sesión
    4. Existen ISPs que direccionan los requerimientos con una IP única
    5. Existen usuarios que no permiten el uso de cookies en sus máquinas
    Teniendo en cuenta lo anterior, se puede sugerir implementar una solución compuesta tal como se describe a continuación:

    1. Definir la política de uso abusivo (Esto implica declarar cuándo se considera que se está extrayendo información del sitio de manera inescrupulosa; por ejemplo, que un mismo usuario visite más de 50 páginas de resultados de una misma búsqueda, o que realice más de 20 búsquedas distintas en un determinado lapso de tiempo)
    2. Definir las acciones a tomar luego de la violación de la política. (Redireccionar a un captcha, denegar el servicio, retardar el servicio, etc.)
    3. Proveer un mecanismo que permita avisar acerca de la violación de la política de acceso. Dependiendo de lo elaborado de la política, esto puede ser ejecutado desde la infraestructura o de la aplicación. Una política sencilla como solo contar el número de requests de una ip dada se puede implementar en la infraestructura. Una política algo más completa como la descrita como ejemplo en el numeral 1, requiere de un a implementación en el lado de la aplicación.
    4. Implementar e integrar los puntos anteriores de manera que cuando el mecanismo de advertencia avise acerca de un posible abuso de acuerdo a las políticas definidas, se tomen las acciones pertinentes.

    Recomendaciones acerca de la política de abuso


    Un acceso abusivo siempre puede ser detectado cuando desde una misma IP son hechos muchos requests. Pero esto mismo puede suceder con el caso de los ISP que tienen una sola ip de salida. Para evitar tachar incorrectamente a los ISP es necesario verificar el tipo de requests que se están haciendo desde una ip sospechosa. En general las consultas sobre los sitios no abarcan más de 10 páginas de resultados de un mismo tema. También de acuerdo a las estadísticas se puede establecer un límite para distintas búsquedas en un tiempo dado por una ip dada; por ejemplo más de 100 búsquedas distintas en 10 minutos indicarían un comportamiento malicioso.

    Entonces ante una violación a la política establecida anteriormente se garantizaría que no se cae en el falso positivo del ISP así que ante este comportamiento sospechoso se podría iniciar con buscar la IP en una base de datos provista por un tercero en la que están registrados los robots en la actualidad. Si este filtro pasa, se continúa con la verificación de si se trata de un robot autorizado como el de google o yahoo; esto se logra a través de un DNS lookup reverso. Aquí entonces si no pasa la validación, se procederá con la acción correctiva.

    Como inconveniente a esta solución, se cita la complejidad de su desarrollo, ya que requiere hacerse del lado de la aplicación que al no tener manejo de sesión, requeriría una implementación con almacenamiento en base de datos por ejemplo.
  • WarNov Developer Evangelist

    .NET Avanzado: Closures

    • 0 Comments

    Voy a ponerlo lo más simple que pueda:

    Un Closure  es una entidad de código que encapsula un comportamiento dado teniendo acceso al contexto en que fue definido; en cristiano, es como una clase, pero no con tanta flexibilidad (solo admite una acción dada) y su estado no puede ser cambiado luego de ser inicializado. En síntesis, una seudoclase más especializada, que consume menos recursos. Y que es más felxible que una estructura, dado que se constuye con delegados, que pueden apuntar a distintos métodos.

    Cómo se construye?

    Tomar el framework 2.0 en adelante, usar sus delegados y métodos anónimos, generar un productor de delegados con un parámetro de configuración y se obtendrá un closure.

    Ha tenido por ejemplo que calcular un impuesto como el IVA que puede variar según el artículo?
    Por ejemplo para una crema dental es de 16% pero para un auto es 25%.

    Entonces el programador bien juicioso se hace el siguiente método:

    double IvaCalc(double tax, double amount);

    Así pues siempre que se vaya a llamar al método se han de pasar ambos parámetros:

    double imp1 = IvaCalc(25, 25800);
    double imp2 = IvaCalc(16, 4);
    dpuble imp3 = IvaCalc(16, 5800);

    etcétera

    Entonces se puede optar por hacer dos métodos; uno por cada tipo de IVA.
    Pero si son 10 tipos de IVA habrán 10 métodos?

    Así que se opta por hacer una clase calculadora de IVA:

    Código clase calculadora de impuestos en C#

    De esta manera basta con instanciar un objeto por cada tipo de IVA y ponerlo a trabajar; esto minimiza la cantidad de código escrita, y es bastante claro:

    IvaCalculator autoCalc=new IvaCalculator(25);
    IvaCalculator prodCalc=new IvaCalculator(16);
    double imp1 = autoCalc(25800d);
    double imp2 = prodCalc(4d);
    double imp3 = prodCalc(5800d);


    Pero de nuevo... si son diez tipos distintos de IVA, creará diez instancias de objeto? Es justo tanto empleo de memoria al tener un objeto completo solo para hacer una operación?
    No lo creo... precísamente para solventar esta situación son útiles los closures.(Entre otras)

    Un closure permite reflejar la simple funcionalidad de la pequeña clase que diseñamos anteriormente, sin incurrir en el overhead del objeto como tal. Para lograrlo, se requiere una forma de mantener un estado (en este caso, la tasa del impuesto) para no tener que estar pasando el parámetro de configuración en cada llamado. Además se requiere una operación sobre ese estado. Cómo lograrlo sin tener que hacer un objeto?

    La operación como tal, se logra con un simple método. Pero este método debe ser configurable en su creación de manera que tenga un estado.

    Para que se pueda configurar es necesario que exista una variable en un ambiente léxico (scope) superior al del método, de manera que esta variable pueda ser inicializada sin necesidad de llamar al método. Esta, será pues la variable que indica el "estado" del método. Pero igual, eso está dentro de una clase. De hecho en C# todo lo que ejecute, ha de estar dentro de una clase. La ventaja ahora, es que vamos a trabajar dentro de la misma clase de ejecución de nuestro flujo. No tendremos que crear más instancias.

    Tanto el parámetro como la operación deben quedar encapsulados dentro de un mismo ambiente léxico dentro de la clase, para que tengamos la unidad requerida para poder generar instancias (pero no de una clase que es lo que queremos instanciar, sino de algo más liviano que llamaremos "enclosure"). Para esto es necesario poder hacer referencia al método dado.

    En .NET qué nos permite hacer referencia a métodos? Si... correcto: los delegados. Entonces generamos un ambiente léxico que tenga al delegado referenciando al método y al parámetro de configuración. Obviamente si estamos dentro de una clase y no queremos generar otra, ese ambiente léxico es un nuevo método. Este método deberá retornar el delegado apuntando a la operación ya configurada como es debido, pero además el método al que apunte el delegado deberá estar declarado inmediatamente, de manera que el parámetro de configuración del mismo sea accesible a éste, desde el método que lo contiene.

    En teoría suena bien. Pero cómo lograr que un delegado apunte a un método que se declara "en línea" junto con éste?

    Ahí es donde entran los métodos anónimos. Son precisamente eso: Métodos declarados en línea donde son requeridos por los delegados. Generalmente, los delegados se han inicializado con el nombre de un método que cumpla el contrato de su firma. Ahora (Framework 2.0 en adelante), no es necesario declarar el método aparte para poderlo referenciar luego por un delegado (lo que impediría acceder al dichoso parámetro de configuración) sino en línea junto con la declaración del delegado:

    delegate int MyDelegate(int a, int b);
    MyDelegate myDel = delegate (int a, int b)
    {
       .....
       return ....
    };

    No olvide el ";".

    Ya con este conocimiento, podemos generar el método que queremos:

    //Este delegado que permitira
    delegate double IvaCalculator_(double tax);

    IvaCalculator_ ivaCalcProducer(double tax)
    {
       return delegate(double amount)

       {
          return amount*tax;
       };
    }


    Exótico no?

    Pero a pesar de ello, logramos lo deseado: El método toma una variable de configuración. Así tenemos estado y manipulación de estado. Lo que haría una clase. Entonces ahora cómo se operaría es muy parecido al uso de clases anterior; solo que ahora no hay overhead por creación de nuevos objetos. Lo que se crean son nuevos delegados. Uno por cada tipo de tasa en este caso. Ellos "cuestan" mucho menos que un objeto.

    IvaCalc_ ivaCalc16=ivaCalcProducer(16);
    IvaCalc_ ivaCalc25=ivaCalcProducer(20);
    double imp1 = ivaCalc25(25800); 
    double imp2 = ivaCalc16(4); 
    double imp3 = ivaCalc16(5800);

    Descargar Ejemplo Completo (Aplicación de consola en C# mostrando el uso de Closures)

    Y listo. Así se construyen y usan los closures. Ahora ya puede ir y alardear un poco con su equipo de desarrollo acerca del misterioso "Closure"!!

     Open mind 4 a different Coding!!!

Page 1 of 1 (10 items)