miércoles, 30 de diciembre de 2009

Novedades Asp.Net 4.0

Estos días en los que el trabajo nos da un poco mas de respiro me he decidido a revisar algunas de las novedades que vamos a poder disfrutar con el lanzamiento de la nueva versión del Framework y del Visaul Studio 2010. Este es el primero de una serie de post en los que iremos viendo algunas novedades que afectaran a los desarrolladores que trabajen con ASP.NET Web.Config Limpios A lo largo de las distintas versiones de asp.net el fichero de conflagración ha ido creciendo, incorporando nuevas características como Ajax, routing o la interacción con IIS. Este aumento nos genere un fichero mucho mas grande y menos legible (el fichero web.config que se añade en un nuevo proyecto en el Visual Studio 2008 sp1 ocupa alrededor de 126 lineas), resulta bastante complicado modificar dicho fichero sin una herramienta como Visual Studio. Pero todo esto ha cambiado en la nueva versión, ahora cuando creemos un nuevo proyecto asp.net 4.0 podremos observar un web.config como este: Esto es posible gracias a que la mayoría de los elementos de conflagración han sido movidos al fichero machine.congif de forma que ahora las aplicaciones heredan del mismo. Esta novedad no aporta funcionalidad alguna pero si permite mayor legibilidad del código que teniendo en cuenta la cantidad de información que tenemos que manejar no es poco. Feliz año nuevo a todos, menos framework y mas Champagne!!

jueves, 3 de diciembre de 2009

Cache de Objectos .Net: Applications Block

Hoy quiero hablar sobre la utilización de la cache en las aplicaciones Asp.net, cuando nos encontramos ante una aplicación que hace numerosas consultas a la base de datos y la mayoría de estas consultas no cambia habitualmente, nos encontramos ante un entorno perfecto para usar la cache. Las ventajas de cachear objetos son obvias, nos permite reducir los tiempos de respuesta de las aplicaciones ya que reducen el número de consultas a la base de datos y esto al final supone la mayoría del tiempo de procesamiento de una página. Llegado este punto en el que tenemos claro que queremos que nuestra aplicación use la cache, debemos decidir dónde vamos a utilizarla y qué vamos a cachear.
Output Cache a nivel de página
Es la forma mas simple de cache, mantiene una copia del HTML que ha sido enviado como respuesta.
Fragment Caching y user controls
Esta técnica se utiliza cuando solo queremos cachear determinadas partes de la página. Estas partes se encapsulan dentro de controles de usuario y luego se marcan con la directiva @OutputCache, indicando el tiempo que se mantendrá el control en memoria.
Caching API, usando el Objeto Cache
Utilizando el objeto cache puedes almacenar cualquier objeto serializable, permite controlar la expiración del objeto en función de varios parámetros, tiempo transcurrido desde su creación, modificación del objeto, modificación del otros objetos, cambios en tablas de la base de datos, ...
Applicattions Block
"Application Blocks son pequeñas (ahora no tan pequeñas) partes de la aplicación, en general bastante necesarias para el desarrollo de aplicaciones corporativas. Se pueden encontrar ejemplos de dichos Application Blocks en http://www.microsoft.com/resources/practices/code.mspx."
Para usas estos bloques de código es necesario instalar el Enterprise Library, una vez instalado ya podremos empezar a configurar la cache, aunque funciona sin necesidad de modificar nada en la configuración.
Este application block soporta la cache en memoria y en almacenamientos de soporte (bases de datos o almacenamientos aislados) .
Configuración
Enterprise Library viene con una herramienta de configuración que nos permite cambiar de forma graficas las opciones de los distintos Blocks.
Lo primero que tenemos que hacer es cargar en la herramienta de configuración el fichero de configuración (web.config) del proyecto en el que queremos utilizar la cache. Si habéis almacenado alguna cadena de conexión en el web.config veréis como la herramienta las reconoce y las sitúa dentro del Application Block de Data Access.
A continuación vereis como se ha creado una nueva sección que corresponde a la cache. Para el ejemplo vamos a mantener los valores por defecto, esto es, tiempo cache 60 segundos, número máximo de elementos en cache 1000, cuando se llega al tope se sacaran de la cache 10 elementos. Guardamos los cambios y cerramos la herramienta.
Uso de la cache
1- Añadir namespaces
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
1- Instanciar object CacheManager
CacheManager cacheManager;
cacheManager = CacheFactory.GetCacheManager("MyCacheManager");

//Cache Manager es el nombre que le hemos dado al CacheManger en la herramienta de configuración
3- Cache de objetos
Usuario user = new Usuario("jorge", "españa", "28");
cacheManager.Add(user.nombre, user, CacheItemPriority.Normal, null, new SlidingTime(TimeSapn.FromMinutes(5)));
Con este ejemplo no se intuye la verdadera necesidad de utilizar este Block, pero si imaginamos situaciones en las que necesitemos realizar la cache en la capa de acceso a datos se vuelve un instrumento de gran importancia.

sábado, 7 de noviembre de 2009

Descubriendo HtmlAgilityPack

Hace algunos años, antes de la popularización de los servicio web y los RSS, era bastante frecuente la tarea de buscar información dentro de una pagina web, recorriendo su código html. Esta tecnica se denomina Screen Scrapping, consiste en descargarse una pagina web, parsear el código Html y sacar la información necesaria. Este trabajo podia convertirse en una tarea complicada. El principal recurso que disponiamos para parsear el código Html eran las expresiones regulares, con ellas se consiguen unos buenos resultados pero tienen el inconveniente de ser muy complejas de construir. HtmlAgilityPack, una gran ayuda! Se trata de una libreria desarrollada en .Net que nos permite bajarnos código html a nuestra memoria, recorrerlo, extraer información y hasta modificarlo. La liberia nos permite ejecutar consultas XPath (Estándar de la W3C que permite realizar consultas los documentos Xml, teniendo en cuenta su estructrura jerarquica) ademas de soportar el tratamiento de páginas mal formadas, algo que es bastante habitual en la red. Bueno y ahora vamos a lo que nos interesa, vamos a ver algo de lo que podemos hacer con este nuevo juguete. Lo primero que tenemos que hacer es descargar la libreria, la podemos encontrar en Codeplex, despues añadimos una referencia en nuestro proyecto a HtmlAgilityPack.dll. En las siguientes lineas de código vamos obtener el titulo de los post de este blog.
static void Main(string[] args)
{
    var client = new System.Net.WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
    var document = new HtmlAgilityPack.HtmlDocument();
    document.LoadHtml(client.DownloadString("http://irokhes.blogspot.com/"));

    //Obtenemos el titulo de cada uno de los post
    foreach (HtmlAgilityPack.HtmlNode node in
          document.DocumentNode.SelectNodes("//h3[@class='post-title entry-title']"))
          Console.WriteLine(node.InnerText.Trim());
}
En el siguiente ejemplo podemos ver como modificar el código de una página, en este caso se trata de como podriamos reparar los enlaces de una página.
 HtmlDocument doc = new HtmlDocument();
 doc.Load("file.htm");
 foreach(HtmlNode link in doc.DocumentElement.SelectNodes("//a[@href"])
 {
    HtmlAttribute att = link["href"];
    att.Value = FixLink(att);
 }
 doc.Save("file.htm");
Por último vamos a ver como Usar sentencias de Linq sobre una página web. En este ejemplo vamos a obtener la url de todas las imagenes que aparecen en el blog.
static void Main(string[] args)
{
   string url = "http://irokhes.blogspot.com/";            
   WebClient client = new WebClient();
   string html = client.DownloadString(url);

   // Load the Html into the agility pack
   HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
   doc.LoadHtml(html);

   List imageNodes = null;
   imageNodes = (from HtmlNode node in doc.DocumentNode.SelectNodes("//img")
             where node.Name == "img"
             select node).ToList();

   foreach (HtmlNode node in imageNodes)
   {
          //Se escribe el atributo src de cada una de las imagenes
          Console.WriteLine(node.Attributes["src"].Value);
   }
}
//
Creo que con estos ejemplos se puede ver la sencillo que es usar la libreria, basta con conocer alguans sentencias de Xpath para poder acceder a cualquier elemento de una págino. Si a usamos esta libreria en conjunto con alguna herramienta como Internet explorer developer toolbar o Firebug podremos examinar la información de cualquier web aunque esta no disponga de una Api especifica para ello.

miércoles, 30 de septiembre de 2009

Usar jQuery con MasterPage

Si alguien ha intentado usar las librerias de jQuery en una proyecto asp.net que las páginas hereden de una página maestra, se habra dado cuenta de que jQuery no funciona. Esto es debido a que la página maestra se encuentra en un nivel de directorios distintos al que se encuentras las paginas hijas. Para solucionar podemos utilizar un pequeño truco, para referenciar el archivo de jquery en la MasterPage lo haremos de la sigueinte manera:
<script src="<%= Page.ResolveUrl("~/Js/ui.core.js") %>"
 language="javascript" type="text/javascript"></script>

miércoles, 9 de septiembre de 2009

Posicionar ModalPopupExtender desde Javascript

Para realizar esto primero tendremos que asignar un manejador al evento Show del control Modal :
function pageLoad() {        
$find('<%= ModalPopupPermisosSinGrid.ClientID  %>').add_showing(onshowing);
}
Una vez hemos capturado el evento Show, definimos la posición de la ventana modal. En este caso la posición depende del tamaño de la pantalla.
function onshowing() {          
var alto = screen.height;
var posicion_Y = alto / 20;        
//seria el mismo funcionamiento para la cordenado X 
$find('<%= ModalPopupPermisosSinGrid.ClientID  %>').set_Y(posicion_Y);
}

martes, 1 de septiembre de 2009

Ordenar ListItemCollection

Cuando tenemos un control como puede ser un DropDownList ó un ListBox, es posible que necesitemos mostrar los elementos de forma ordenada. Para ello dependiendo de la forma que hayamos cargado el control, la ordenación sera mas o menos sencilla. En el caso de que nuestro control este enlazado a datos, la forma más sencilla seria ordenar los elementos antes de ser enlazados. Existen otros escenarios en los que podemos permitir al usuario manipular esa lista o bien el caso típico que tenemos dos listbox en los que podemos pasar datos de uno al otro. Para esto tendremos que convertir la colección de items a un array y mediante LinQ realizamos la ordenación. La función podria ser la siguiente:
private void OrdenarListBox(ListBox listBoxControl)
{

   //se convierte la coleccion de items a un array
   ListItem[] myListItemArray = new ListItem[listBoxControl.Items.Count];
  lbxRecursosAsignados.Items.CopyTo(myListItemArray, 0);
   //mediante linq se ordena el array por el campo Texto del item
   IEnumerable<ListItem> query = from r in myListItemArray orderby r.Text ascending select r;
   //se enlaza el array al control
   lbxRecursosAsignados.DataSource = query;
   lbxRecursosAsignados.DataBind();
}

jueves, 27 de agosto de 2009

Compatibilidad de los navegadores con CSS

En algunas ocasiones conseguir que una web se vea correctamente en todos los navegadores puede resultar un verdadero infierno. Para solucionar los diversos problemas de estandares y compatibilidades podemos optar por usar diferentes hojas de estilo dependiendo del navegador. A continuación podeis ver un ejemplo:

<!--[if gte IE6]>
<link rel="stylesheet" type="text/css" href="styles/ie.css" />
<! [endif] -->
Otra forma de aplicar distintos estilos a una web en función del navegador es haciedo esta diferenciación dentro de la hoja de estilo, en este caso podemos ver varios ejemplos de como hacerlo.

#something { color: red; } /* Se aplica a IE6 y superior. */
*+html #something { color: green; } /* Se aplica a IE7. */
* html #something { color: blue; } /* Se aplica a IE6. */


margin-left: 5px; /* Margen izquierdo para todos los navegadores */
.margin-left: 7px; /* Margen izquierdo de 7px para IE6 y IE7, los demas navegadores todavia seguiran manteniendo el margen de 5px inicial */
_margin-left: 6px; /* Sólo IE6 leerá y entendera este estilo y aplicará el valor */

Por último podemos recurrir a otro pequeño truco, si en nuestra hoja de estilos añadimos una propiedad y le anteponemos '//' internet explorer si que interpretara esta propiedad pero el resto de navegadores no.
#nonie{//display: none;}

#iebased{
       display: none;
       //display: visible;
}
En esta caso si tuvieramos dos Div´s como los siguientes :

<div id="nonie"> Tu <i>no estas</i> utilizando Internet Explorer. </div>

<div id="iebased"> Tu <b>estas</b> utilizando Internet Explorer. </div>

En este caso solo veriamos la capa correspondiente en función del tipo de navegador que usemos. Este ultimo truco no es demasiado elegante pero si muy funcional.

jueves, 23 de julio de 2009

Deshabilitar la cache de una pagina asp.net en Firefox

Para deshabilitar la cache de una página asp.net podemos hacerlo de diversas formas, desde IIS (indicando que la página caduque inmediatamente), añadiendo metas a las cabeceras de la pagina e inclucuso podemos hacerlo también desde código con esta instrucción: HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache); Después de probar las diversas técnicas he descubierto que no todas funcionan con todos los navegadores (en esta ocasión es Firefox quien pone la nota discordante), asi que para conseguir deshabilitar la cache para una página concreta lo mejar sera añadir etiquetas META. La siguiente función muestro como añadir las etiquetas desde código. public void DeshabilitarCache() { Response.ClearHeaders(); Response.AppendHeader("Cache-Control", "no-cache"); Response.AppendHeader("Cache-Control", "private"); Response.AppendHeader("Cache-Control", "no-store"); Response.AppendHeader("Cache-Control", "must-revalidate"); Response.AppendHeader("Cache-Control", "max-stale=0"); Response.AppendHeader("Cache-Control", "post-check=0"); Response.AppendHeader("Cache-Control", "pre-check=0"); Response.AppendHeader("Pragma", "no-cache"); Response.AppendHeader("Keep-Alive", "timeout=3, max=993"); Response.AppendHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT"); }

lunes, 20 de julio de 2009

Ordenar un Dropdownlist con Linq

El siguiente codigo muestra una función que sirve para ordenar un Combo utilizando, como campo de ordenación el texto que se muestra en cada uno de los items. ///Funcion que ordena los elementos de un Dropdownlist protected void OrdenarDropDownList(DropDownList drp) { drp.DataSource = drp.Items.Cast() .OrderBy(o => o.Text) .ToList(); drp.DataBind(); }

jueves, 25 de junio de 2009

Comprobar si una página es válida desde javascript

En el siguiente post veremos como usando los controles de validación de asp.net se puede comprobar desde javascript si la pagina es valida o no. Esto puede ser útil para para mostrar u ocultar información en función del resultado de la validación. Para hacer la comprobación solo tendremos que añadir el siguiente codigo en una funcion javascript //nombre del grupo de validadores que queremos comprobar //en caso de dejarlo en blanco se comprueba la pagina entera var validationGroupName = ""; if (typeof(Page_ClientValidate) == 'function') { var validationResult = Page_ClientValidate(validationGroupName); if (validationResult == true) { //Cuando entramos aqui, sabemos que la página o el los controles pertenecientes //al grupo de validación seleccionado son válidos } }

jueves, 28 de mayo de 2009

Recorrer los nodos de un TreeView control desde javascript

Hace unos dias me surgio la necesidad de trabajar con el control treeview, mas concretamente he tenido que realizar una busqueda sobre sus nodos. Para llevar a cabo esta tarea tenia que recorrer todo el arbol y comprobar si el valor de alguno de los nodos coincidia con el texto que un usuario introduciria en una caja de texto. Esta tarea me ha llevado a investigar mas profundamente el control Treeview, es un cotrol digamos... diferente. Para recorrer el control primero de todo he tenido que fijarme en el html que se genera, este esta compuesto por capas y tablas. Un nodo es una tabla con una fila y dentro de esas filas celdas, que correspoden con la imagen de expandir colarpsar, la imagen que el nodo tenga y el nombre o texto del nodo. Si este nodo tiene nodos hijos, estos iran dentro de una tabla cada uno de ellos y todos ellos dentro de una etiqueta
que por identificador tendra el del nodo padre más un el sufijo "Nodes". Basandonos en esto el código seria el siguiente: //obtención de la cadena a buscar var keysrch = $get('<%=txtBuscar.ClientID %>').value; //obtencion del objeto Treeview var tree = document.getElementById('<%=arbolListines.ClientID%>'); if(keysrch != '') { //obtencion de todas las tablas que hay dentro del control var tables = tree.getElementsByTagName('table'); if(tables) { for (var i = 0, j = tables.length; i < j; i++) { //dentro de cada tabla accedemos a los enlaces que esta continen links = tables[i].getElementsByTagName('a'); if(links) { for (var x = 0, y = links.length; x < y; x++) { //si el primer nodo no es una imagen significa que no es ni el icono +/- //tampoco es la imagen que hemos asociado a nuestro nodo, con lo que ya hemos //llegado a la posición en la que se encuentra el texto que es lo que nos interesa if(links[x].firstChild.nodeName.toLowerCase() !='img') { // procesamos el texto para buscar si la cadena que de búsqueda esta dentro del nombre del nodo var result = links[x].innerHTML.toLowerCase().indexOf(keysrch); if (result != -1) { //hemos encontrado el nodo que buscabamos //procesar..... }//fin del if que comprueba que estemos buscando solo en el enlace que contiene el nombre } }//fin del bucle for que recorre todos los enlaces de cadad nodo } }//fin del bucle for que recorre las tablas que genera el control treeview en HTML }

miércoles, 20 de mayo de 2009

Cachear imagenes creadas en un HttpHandler

Existen varias maneras de mejorar el rendimiento de una aplicación web, una de las más importantes es el cacheo de datos y más concretamente, cachear imagenes. Existen algunos escenarios en los cuales conseguir cachear los datos no es trivial, uno de ellos es cuando tenemos una imagen almacenada en una base de datos en formato BLOB, en este casi si queremos mostrar la imagen en nuestra web, una manera de hacerlo es creando un Controlador genérico (.ashx). Si hacemos esto deberemos manejar manualmente el cacheo de imagenes. El siguiente fragmento de código muestra como habilitar la cache:

//creacion de un objeto TimeSpan que va a indicar la duración de la cache

TimeSpan freshness = new TimeSpan(0, 0, 10, 0);

//se configura el tiempo de expiración de la cache

context.Response.Cache.SetExpires(DateTime.Now.Add(freshness));

//configuracion del ámbito de la cache

context.Response.Cache.SetCacheability(HttpCacheability.Public);

context.Response.Cache.SetValidUntilExpires(false);

Posteriormente se se envia la salida de la imagen

context.Response.ContentType = "image/gif";

context.Response.OutputStream.Write(buffer, 0, buffer.Length);

martes, 19 de mayo de 2009

Como saber si si ha ocurrido un Postback Asíncrono Parcial

Con la llegada Ajax debemos tener en cuenta que actualmente existen dos tipos de Postback, uno podriamos llamarlo Full Postback, en él se recarga toda la página. Con ajax surge el concepto de Partial Postback, es una ida al servidor que solo actualiza una parte de la página. En ocasiones puede ser interesante para el control de nuestras aplicaciones si un Postaback ha sido parcial o total, para ello tendremos que obtener una instancia del ScriptManager de nuestra página a traves del método GetCurrent y comprobando el valor de la propiedad IsInAsyncPostBack. A continuación podemos ver un ejemplo: protected void Page_Load(object sender, EventArgs e)

{

if (Page.IsPostBack)

{

//Se obtiene comprueba la propiedad IsInAsyncPostBack

if (ScriptManager.GetCurrent(this.Page).IsInAsyncPostBack)

{

// TODO logica para una recarga parcial

}

else

{

//logica para un postback total

}

}

}

jueves, 14 de mayo de 2009

Enlazar un enumerado a un Dropdownlist c#

En muchas ocasiones en nuestras aplicaciones definimos enumerados para hacer un manejo mas eficiente de los datos, muchas veces queremos mostrarlos en un combo para que el usuario seleccione. Para hacer esto podemos enlazar el enumerado al control DropdownList public enum MiEnumerado {Lunes,Martes,Miercoles} MiDropDownList.DataSource = Enum.GetNames(typeof(MiEnumerado)); MiDropDownList.DataBind(); Para acceder al valor seleccionado podriamos hacerlo de la siguiente manera: MiEnumerado miEnun = (MiEnumerado)Enum.Parse(typeof(MiEnumerado),MiDropDownList.SelectedValue); De esta forma tenemos el valor seleccionado en forma de enumerado nuevamente.

martes, 12 de mayo de 2009

Ciclo de vida de una pagina Asp.Net

Gracias a un gran compañero y mejor profesional (para que no te quejes Rafa) os dejo el esquema del ciclo de vida completo de una pagina asp.net.
(Haz click en la imagen para verla a tamaño completo)

Saber que control ha provocado el Postback

En algunas ocasiones nos gustaria saber control ha provocado la recarga (postback) de la página para esto podemos hacerlo de dos formas dependiendo de si es una recarga parcial (ajax) o un postaback total de la pagina. 1.-Si es una recarga parcial de la pagina //obtenemos la página actual Page page = (HttpContext.Current.Handler as Page); //mediante el Scriptmanager accedemos al control que ha hecho la recarga parcial de la misma string ctrlname = ScriptManager.GetCurrent(page).AsyncPostBackSourceElementID; Control control = page.FindControl(ctrlname); 2.-Si es una recarga total ctrlname = page.Request.Params["__EVENTTARGET"]; Esto funciona conrrectamente con casi todos los controles pero No con Botones, esto es debido a que los botons cuando se pintan en html no llaman a la función __doPostBack de Javascript y por tanto __EVENTTARGET nunca va a tener valor, para conseguir esto os dejo un enlace en el que muestran como conseguirlo para todo tipo de controles. Es un articulo muy útil de Ryan Farely.

Determining the Control that Caused a PostBack

lunes, 11 de mayo de 2009

TreeView SelectedNodeStyle no funciona sin Postback

Después de pasar un buen rato trabajando con el control Treview de asp.net (la version 2.0 del control, con la uno este problema no existe) me surgio un problema que con el que no contaba, el árbol que yo estaba generando no hacia postback cuando se producia un click en uno de los nodos, este que a priori no deberia suponer un problema, lo es cuando queremos personalizar el estilo del nodo seleccionado, en esta situación no se aplicaba el estilo. Esto se puede hacer de forma declarativa medienta las propiedades SelectNodeStyle. <"asp:treeview id="arbolListines" runat="server" backcolor="Aqua" bordercolor="Black" bold="true" > Para que el estilo sea reconocido de forma correcta debemos añadir la siguiente propiedad al control Treeview: Target="_self" De esta forma conseguiemos que funcione correctamente.

Acceder a un control dentro de un ContentPlaceHolder desde JavaScript

Un pequeño problema a la hora de usar las MasterPage es que al introducir controles dentro de los ContentPlaceHolder, el ClientId de estos controles aparece modificado, se le añade un prefijo con el nombre de su contenedor (ContentPlaceHolder). Esto solo nos afecta si queremos acceder a estos controles desde el cliente (javascript) . Un ejemplo seria un TextBox con el Id = txtNombre, este apareceria en nuestro codigo html como
ctl00_ContentPlaceCuerpoPagina_txtNombre

La solución fácil seria acceder usando el nombre completo

document.getElementById("ctl00_ContentPlaceCuerpoPagina_txtNombre").value

Esto seria poco elegante y ademas peligroso, ya que si en algun momento se cambia el nombre
del ContentPlaceHolder,esa sentencia ya no seria valida. Una forma efectiva de acceder al control seria.


document.getElementById('<%=txtNombre.ClientID %>').value