Cuestiones sobre ASP.NET
Transcripción
Cuestiones sobre ASP.NET
dnm.todotnet.qa Dino Esposito Cuestiones sobre ASP.NET Este mes responderemos algunas preguntas relacionadas con el desarrollo Web y ASP.NET en particular. Las cuestiones abordan temas que van desde la importación de datos de fuentes externas y sitios Web,hasta tareas asíncronas y la representación de imágenes almacenadas en bases de datos. Dino Esposito es mentor de Solid Quality Learning y autor de “Programming Microsoft ASP.NET 2.0 Core Reference” y “Programming ASP.NET 2.0 Applicatinos Advanced Topics”, ambos de Microsoft Press.Afincado en Italia, Dino es un ponente habitual en los eventos de la industria a nivel mundial.Visita su blog en: http://weblogs.asp.net/despos. Puede enviarle sus consultas a [email protected] tran información actualizable desde otros sitios: por ejemplo noticias deportivas. No creo que ninguno de mis clientes realmente quisiera tal tipo de servicio pero sí que pienso que la importación de datos externos desde otros sitios Web sería una poderosa característica a considerar. Hasta donde yo sé, hay dos formas típicas de implementar algo similar. Una consiste en utilizar un servicio Web para obtener cualquier información contractual expuesta por el sitio. Esto significa, sobre todo, algún tipo de acuerdo entre las dos partes. Cuanta más información valiosa, más tendrás que pagar por ella, probablemente. Desde un punto de vista tecnológico, simplemente se accede a la información de entrada (normalmente, cadenas), y la muestras en la forma adecuada. El segundo enfoque, supone suscribirse a algún origen de datos RSS. Es un sitio que expone información publicable y la hace disponible, virtualmente a cualquier cliente, gratis. En este caso, abres un socket hacia el destino RSS, obtienes la información –una cadena XML– y la incorporas en tus páginas. En ambos casos, un acuerdo implícito o explícito existe entre tu sitio y el del origen de la información. Pero, para decirlo todo, existe un tercer enfoque: el clásico Screen-scrapping. Aunque nacida históricamente en mainframes hace 25 años, la técnica recobró actualidad con el advenimiento de las páginas Web. Consiste en la posibilidad de descargar una página completa y analizarla para extraer la información válida. Por ejemplo, se puede descargar una página de cotizaciones de bolsa, y mostrar solo aquellas en las que estás interesado. Se analizan los contenidos eliminando todo menos los 3 ó 4 valores a buscar. “ Para leer orígenes RSS, se utilizan típicamente herramientas como RssBandit o SharpReader. ¿Cómo podrías leer uno de estos orígenes en una página ASP.NET? Lo que muchos sitios Web hacen es utilizar un control de usuario compuesto Si el sitio Web de origen no tiene una oferta RSS, ésta sería mi opción predilecta. Screen-scrapping debería considerarse únicamente como último recurso. Para leer orígenes RSS, se utilizan típicamente herramientas como RssBandit o SharpReader. ¿Cómo podrías leer uno de estos orígenes en una página ASP.NET? Lo que muchos sitios Web hacen (incluyendo las páginas MSDN) es utilizar un control de usuario compuesto. La clave de este control, contendría un código similar al del fuente 1. La variable text contiene la salida del origen en formato XML. El contenedor ProcessFeed recorre los elementos XML y construye un texto imprimible en HTML. Si seleccionamos una aproximación más elegante, podríamos devolver un array de objetos personalizados a partir de ProcessFeed que solamente almacenaran líneas individuales para ser transformadas en lenguaje de marcas posteriormente. El código del fuente 2 muestra cómo construir una lista de enlaces a los últimos “posts”. ” <<dotNetManía << Algunos de los sitios Web que visito regularmente mues- 49 << dnm.laboratorio.net “ WebRequest req; string rssData = String.Empty; req = WebRequest.Create(RSSFEED); using (WebResponse response = req.GetResponse()) { StreamReader reader; string text = String.Empty; using (reader = new StreamReader(response.GetResponseStream())) { text = reader.ReadToEnd(); } Cualquier operación puede ser fácilmente catalogada en dos formas:vinculada a la CPU o a un proceso de entrada/salida // Process the RSS data rssData = ProcessFeed(text); } Fuente 1 string ProcessFeed(string feed) { StringBuilder sb = new StringBuilder(); XmlDocument doc = new XmlDocument(); doc.LoadXml(feed); XPathNavigator nav = doc.CreateNavigator(); XPathNodeIterator iterator; // Title and description iterator = nav.Select(“/rss/channel/title”); iterator.MoveNext(); sb.AppendFormat(“<h3>{0}</h3>”,iterator.Current.Value); iterator = nav.Select(“/rss/channel/description”); iterator.MoveNext(); sb.AppendFormat(“<i>{0}</i>”, iterator.Current.Value); XmlNodeList items=doc.SelectNodes(“/rss/channel/item”); sb.Append(“<ul>”); foreach(XmlNode n in items) { XmlNode title = n.SelectSingleNode(“title”); XmlNode link = n.SelectSingleNode(“link”); XmlNode date = n.SelectSingleNode(“pubDate”); sb.AppendFormat(“<li><a href=\”{0}\”>{1}</a> on {2}</li>”, link.InnerText, title.InnerText, date.InnerText); } sb.Append(“</ul>”); return sb.ToString(); } <<dotNetManía Fuente 2 50 Este código puede ser fácilmente incorporado en un control de usuario compuesto hecho a partir de una tabla o rejilla. He construido varias soluciones utilizando tareas asíncronas, pero reconozco que no he prestado demasiada atención al término I/O bound (vínculo). ¿Significa esto que cualquier operación asíncrona no estrictamente relacionada con entrada/salida es perniciosa? Cualquier operación puede ser fácilmente catalogada en dos formas: vinculada a la CPU o a un proceso de entrada/salida. En el primer caso, el tiempo de compleción está determinado por las características de la propia CPU y la memoria disponible. En el otro, la situación es radicalmente distinta, y la CPU espera –la mayor parte del tiempo– a que los dispositivos de entrada/salida terminen su trabajo. Ahora bien, ¿cuál es el objetivo último de un proceso asíncrono? Un empleo típico es cuando necesitamos que nuestra interfaz de usuario no se “congele” mientras termina algún proceso en background, de larga duración potencial. En este sentido, no hay ninguna diferencia importante entre los dos tipos de operaciones. Esto es correcto en tanto que estemos considerando escenarios de “clientes ricos”, como aplicaciones Windows Forms. Para aplicaciones ASP.NET las cosas son algo distintas. Si has escrito ese código para aplicaciones Windows no debe de haber problema. ¿Qué operaciones son buenos candidatos a implementarse como páginas Web asíncronas? Para decirlo en otra forma, ¿qué operaciones requieren, o al menos, sugieren claramente la adopción de páginas asíncronas en una aplicación ASP.NET? Intentemos formalizar brevemente el concepto de proceso asíncrono dentro del contexto de ASP.NET. “ La necesidad del proceso asíncrono deriva de un tiempo excesivo en el tráfico de la información de entrada/salida, respecto del tiempo de proceso. ” ” “ cualquiera que sea el origen de la imagen a mostrar, sólo puede incluirse en una página a través del elemento <img> y, por consiguiente, vía URL ” teriores releases y en la versión final. Sin embargo, el problema que me condujo a esa situación al principio no desaparece. ¿Cómo puedo construir mi propio control de imagen dinámico en ASP.NET 2.0? En ASP.NET, dispones de dos controles de servidor para mostrar imágenes: Image y HtmlImage. Ambos controles suministran un ligero nivel de abstracción sobre algunas de las propiedades del elemento <img> de HTML. Ambos controles, en definitiva, solo permiten referenciar imágenes vía URL, y establecer algunos atributos de presentación. Como sugieres, en el mundo real, los gráficos pueden venir de una gran variedad de orígenes. Por ejemplo, pueden provenir de un fichero, se pueden leer a partir de un campo de una base de datos, o se pueden generar dinámicamente en memoria utilizando una API gráfica. Solo en el primer caso –el del fichero en disco– podemos aplicar adecuadamente el elemento <img> y el API de ASP.NET. En todos los otros casos, los programadores deben escribir su propio código para conseguirlo. Veamos cómo. El hecho es que, cualquiera que sea el origen de la imagen a mostrar, sólo puede incluirse en una página a través del elemento <img> y, por consiguiente, vía URL. Toda la lógica empleada para obtener la imagen, debe de ser embebida en código accesible a través de una URL. En ASP.NET, la URL puede apuntar a un manejador HTTP personalizado. El control DynamicImage, de hecho, se apoya en el manejador cacheimageservice.axd, un manejador incrustado que ha sido liberado de la plataforma en alguna manera. En ASP.NET 2.0, comienzas por crear un manejador análogo HTTP y diseñarle para aceptar en la cadena de consulta cualquier información que pueda ser útil para identificar la imagen y su origen. El viejo control DynamicImage encapsulaba mucha de esta información (cadenas de conexión, consultas, ID) en sus propios parámetros, aislando, por tanto, el manejador HTTP subyacente del desarrollador. Este manejador ejecutará cualquier código necesario para obtener los bytes de la imagen, establecer el tipo MIME apropiado y devolver los bytes. Para evitar consultas repetitivas y algunos ciclos de CPU, el manejador HTTP puede almacenar imágenes en el caché y acceder a ellas la próxima vez que se necesiten. Traducción por Marino Posadas <<dotNetManía La necesidad del proceso asíncrono deriva de un tiempo excesivo en el tráfico de la información de entrada/salida, respecto del tiempo de proceso. En tales situaciones, la CPU está en estado de espera o es infrautilizada la mayor parte del tiempo, esperando que algo suceda. Y en particular, en las operaciones de entrada/salida en el contexto de ASP.NET, porque los subprocesos en servicio están bloqueados también y el pool de servicio de subprocesos es un recurso finito y crítico. Se obtienen mejoras en el rendimiento si se utilizan modelos asíncronos en operaciones de entrada/salida. En la implementación de .NET Framework, cuando se hace una llamada asíncrona no existen subprocesos bloqueados mientras la operación está pendiente. Ejemplos típicos de operaciones de entrada/salida son todas las operaciones que requieren acceso a algún tipo de recurso remoto o que interaccionan con dispositivos hardware externos. Las operaciones sobre bases de datos o servicios Web no locales, son las más comunes para considerar la creación de páginas asíncronas. En ASP.NET, las operaciones de larga duración de CPU (por ejemplo, algún algoritmo que requiera actuar sobre datos en memoria) son también buenas candidatas a una implementación asíncrona para mantener en número de subprocesos administrados en un nivel suficientemente alto. En este caso, sin embargo, todavía está recargada con algo de trabajo, y la ganancia de rendimiento es menor que en las operaciones de entrada/salida. En suma, cualquier tarea de larga duración debería de ser llamada de forma asíncrona, tanto en Windows como en ASP.NET. En este último caso, sin embargo, es particularmente importante en los procesos de entrada/salida. Si uno de estos procesos (por ejemplo, la llamada a un servicio Web), es implementado de forma asíncrona, la CPU del servidor no se ve afectada, y puede procesar con prontitud otras peticiones. Para operaciones vinculadas a la CPU, también las llamadas asíncronas pueden ofrecer algo de mejora en Windows, al ejecutarse en un subproceso diferente. Para aplicaciones ASP.NET, sin embargo, no debieran esperarse grandes mejoras. Siempre es mejor la llamada asíncrona pero las páginas se mostrarán lentamente, ya que la CPU tiene que realizar un gran trabajo para generarlas. Una aproximación más eficaz sería separar las operaciones de larga duración a un servidor remoto y transformar la tarea tipo CPU en una del tipo entrada/salida. En los primeros días de ASP.NET 2.0 –trabajo con ella desde las primeras versiones alpha, en verano de 2003– podía referenciar fácilmente imágenes almacenadas en una base de datos SQL Server usando control a medida –el control <asp_ DynamicImage>–. Este control, fue eliminado en pos- [email protected] [email protected] << dnm.laboratorio.net 51