jueves 1 de julio de 2010

IIS 7, Habilitando Compresión de Respuesta

Hoy quiero comentarles sobre la posibilidad que tenemos en IIS para comprimir las páginas servidas. Al usar esta opción podremos disminuir considerablemente el trafico de RED entre nuestro servidor y los navegadores WEB clientes.

Para analizarlo me he basado en una página de consulta de disponibilidad de vuelos; como veremos en las imágenes de abajo, paso de recibir 1 546KB a recibir solo 301KB, menos del 20% del valor original, optimizando el ancho de banda consumido en más de un 80%.

Compresion NO

Compresion SI

La primera imagen es el resultado de consultar la página (AereoBuscador) sin haberle habilitado la compresión en el IIS. Y el tamaño de la respuesta obtenida es de: 1 546 KB.

La segunda imagen corresponde a la misma página (AereoBuscador) pero en esta ocasión con la compresión activada en el IIS. Y la respuesta es de  301 KB.
El 19.5% del valor anterior.

 

Pasos para Activar la Compresión en el IIS 7

Para activar esta opción basta con abrir IIS y localizar el sitio al que le queremos habilitarle la compresión, y una vez situados en el sitio abrimos la opción de compresión (figura de la izquierda) y marcamos los check (imagen de la derecha)

Compresion Step 1 Compresion Step 2

Así de fácil...

Nota: He de puntualizar que la compresión dinámica, aunque por un lado mejora el consumo de ancho de banda, también consume más procesador, con lo que si no se usa en la proporción adecuada puede reducir el rendimiento global del servidor.

jueves 24 de junio de 2010

Como evitar Cache de Página en el Explorador (IE, Firefox…)

Si estas desarrollando con ASP.NET y quieres evitar que el explorador almacene en Caché una determinada página Web, tienes varias alternativas para lograrlo, a continuación expongo como evitar el almacenamiento en caché mediante programación.

Cache de Página mediante Programación

En el Page_Load de la página en cuestión colocar el siguiente código (cualquiera de las 2 líneas valdría)

Response.Cache.SetCacheability(HttpCacheability.ServerAndNoCache);
Response.Cache.SetCacheability(HttpCacheability.NoCache);

Cada vez que se haga clic en un botón hacia delante o hacia atrás del explorador, o cualquier evento que genere un POSTBACK, se solicitará al servidor una nueva versión de la página.

Nota: Este mismo resultado (almacenamiento de página en caché) podemos lograrlo de forma declarativa usando la directiva OutputCache. Ej:

<%@ OutputCache Duration="120" VaryByParam="None"%>

viernes 11 de junio de 2010

Caché Web con CacheDependency en ASP.NET (C#)

Veamos un ejemplo práctico de como implementar el trabajo con Cache en ASP.NET usando HttpRuntime.Cache (System.Web.Caching.Cache).

Si estamos desarrollando una Aplicación Web con ASP.Net y deseamos implementar y usar Caché, este tutorial te será de utilidad. Existen varias soluciones para implementar el trabajo con Caché (AppFabric, EnterpriseLibrary.Caching, y otras que no vienen a caso ...), nuestro propósito es implementar nuestra propia lógica de Caché usando la clase Cache presente en el ensamblado System.Web.dll.

Adicionalmente crearemos una relación de dependencia entre el elemento almacenado en Caché y su correspondiente archivo en disco, pero de esto hablaremos mas adelante, de momento pasemos al código.

HttpRuntime.Cache & CacheDependency, Ejemplo de Código

Lo que haremos serán 2 métodos:

  1. Put: Escribir un objeto en Caché, y crear además una relación de dependencia con un archivo que también escribiremos en disco.
  2. Get: Leer un objeto de la Caché.

public static class MiAppCacheDependency

{

  public static bool Put(Object obj, string nameCache)

  {

    try

    {

      string filePathFullName = @"C:\Cache\" + nameCache + ".xml";

     

      File.WriteAllText(filePathFullName, obj.Serializa());

      // Crear la dependencia de la cache con el archivo 

      HttpRuntime.Cache.Insert(nameCache, obj, new CacheDependency(filePathFullName));

    }

    catch

    {

      throw new Exception("Error al escribir en cache, posiblemente no            

                           exista la carpeta CacheDependency.");

    }

    return true;

  }

 

  public static T Get<T>(string nameCache)

  {

    try

    {

      object cache = HttpRuntime.Cache[nameCache];

      if (cache == null) return default(T);

      return (T)cache;

    }

    catch { return default(T); }

  }

}

 

Veamos ahora como usar estos métodos. Imaginemos que tenemos una clase (Aerolíneas) para la gestión de las distintas aerolíneas. En esta clase tendremos:

  1.  CacheKey: Una propiedad de la clase que contendrá el nombre con que guardaremos las aerolíneas en la Caché.
  2. CacheGet: Un método que leerá las aerolíneas desde la caché, si estas no estuvieran, las leerá de la base de datos y la colocará en la caché.
  3. CachePut: Un método que escribirá las distintas aerolíneas en la caché.

namespace dllMiApp.Aerolineas

{

  /// <summary>

  /// Clase para la gestión de los Aerolineas

  /// </summary>

  public partial class Aerolineas

  {

    private static string CacheKey = "Aerolineas";

    /// <summary> 

    /// Escribe o inserta en cache las aerolíneas 

    /// </summary> 

    public static bool CachePut(List<Aerolinea> lstAerolineas)

    {

      return MiAppCacheDependency.Put(lstAerolineas, CacheKey);

    }

    /// <summary>

    /// Lee las aerolíneas desde cache. Sino existiera en chache, las lee de la BD

    /// </summary>

    public static List<Aerolinea> CacheGet()

    {

      List<Aerolinea> lstAerolineas = MiAppCacheDependency.Get<List<Aerolinea>>(CacheKey);

      if (lstAerolineas == null)

      {

        lstAerolineas = Aerolineas.GetAerolineasValidas();

        CachePut(lstAerolineas);

      }

     

      return lstAerolineas;

    }

  }

}

Nota: En los distintos métodos que actualicen las aerolíneas, deberíamos actualizar también su valor en la caché. Al existir una relación de dependencia entre la caché y un archivo en disco, garantizamos que al modificar la caché a través de una aplicación, todas las demás aplicaciones que usen la dependencia, se enterarán de la modificación.

 

Artículos Relacionados:

martes 8 de junio de 2010

Crystal Reports Visual Studio 2008, 2005, 2003 Paquete de Distribución

Hoy quiero comentar sobre un error que recientemente me ocurrió al mudar una Aplicación Web ASP.NET hacia un nuevo servidor.

El Error

ex.InnerException: System.IO.FileNotFoundException: No se puede cargar el archivo o ensamblado 'CrystalDecisions.CrystalReports.Engine, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304' ni una de sus dependencias. El sistema no puede encontrar el archivo especificado…

 

La Causa

En el nuevo servidor no estaba instalado el Paquete de Distribución de Crystal Reports, por ende no encontraba las dll o ensamblados necesarios para poder visualizar un fichero rpt.

 

La Solución

Para solucionarlo basta con instalarse el Paquete de Distribución de Crystal Reports para .Net. En mi caso concreto como ya tenía instalado dicho Paquete de Distribución en mi ordenador de desarrollo, pues solo tuve que ir a la carpeta:

  • C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\CrystalReports10_5

y copiar hacia el servidor los ficheros:

  1. CRRedist2008_x86.msi (En caso de usar SO 64bit –> CRRedist2008_x64.msi)
  2. CRRedist2008_x86_es.msi (En caso de usar SO 64bit –> CRRedist2008_x64_es.msi)

Posteriormente solo te queda instalarte ambos paquetes y todo listo. El segundo archivo es el paquete de idiomas, así que te aconsejo que respetes el orden de instalación.

Y todo listo, ya podrás visualizar tus informes Crystal Reports.

Si usas una versión diferente, o quieres profundizar más, te aconsejo le des un vistazo al siguiente enlace.

Podrás descargarte los diferentes Runtime Packages para Crystal Reports desde aquí.

sábado 5 de junio de 2010

C#, Serializar JSON (DataContract)

Veamos un ejemplo práctico y simple de como serializar o seriar un objeto con formato JSON. Para ello definiremos una clase a la cual le crearemos una instancia y después la serializaremos.

Definir la clase a serializar

Para poder realizar la serialización JSON de cualquier clase usando DataContractJsonSerializer, esta debe cumplir las siguientes condiciones:

  • La clase debe tener definido el atributo [DataContract].
  • Cada elemento de la clase que deseemos serializar debe definir el atributo [DataMember]

[DataContract]

internal class Pais

{

  public int IdPais { get; set; }

 

  [DataMember]

  public string CodPais { get; set; }

  [DataMember]

  public string Nombre { get; set; }

}

 

Definir el Método que Serializa el objeto en JSON

Definiremos el método extensor que dado un objeto cualquiera, lo serializa en formato JSON. Es importante puntualizar que el tipo del objeto debe implementar DataContract. Veamos el código:

public static class JsonSerializer

{

  /// <summary>

  /// Método extensor para serializar JSON cualquier objeto

  /// </summary>

  public static string SerializaToJson(this object objeto)

  {

    string jsonResult = string.Empty;

    try

    {

      DataContractJsonSerializer jsonSerializer =

        new DataContractJsonSerializer(objeto.GetType());

      MemoryStream ms = new MemoryStream();

      jsonSerializer.WriteObject(ms, objeto);

      jsonResult = Encoding.Default.GetString(ms.ToArray());

    }

    catch { throw; }

    return jsonResult;

  }

}

Y por último solo nos queda usar el método extensor recién definido, veamos un ejemplo de uso:

class Program

{

  static void Main(string[] args)

  {

    List<Pais> lstPaises = new List<Pais>() {

       new Pais() { IdPais=31, Nombre = "Francia", CodPais = "FR" },

       new Pais() { IdPais=53, Nombre = "Cuba", CodPais = "CU" }};  

    string json = lstPaises.SerializaToJson();

    List<Pais> lst2 = json.DeserializarJsonTo<List<Pais>>();

  }

}

El resultado de seriar el objeto lstPaises sería:

[{"CodPais":"FR","Nombre":"Francia"},{"CodPais":"CU","Nombre":"Cuba"}]

En el código anterior vemos que hemos llamado a un método extensor que aún no hemos definido (DeserializarJsonTo), dicho método hará justo lo contrario (deserializar) a partir del string en formato JSON obtener el objeto de tipo List<Pais>. Veamos la definición del método:

public static T DeserializarJsonTo<T>(this string jsonSerializado)

{

  try

  {

    T obj = Activator.CreateInstance<T>();

    MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonSerializado));

    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());

    obj = (T)serializer.ReadObject(ms);

    ms.Close();

    ms.Dispose();

    return obj;

  }

  catch { return default(T); }

}

 

Artículos Relacionados:

viernes 21 de mayo de 2010

Clonar Objeto con C#

C# Clonar un objeto complejo: Veamos un ejemplo práctico y sencillo de como clonar o duplicar un objeto de estructura compleja.

La mayoría de los datos que solemos utilizar en nuestras aplicaciones, son tipos de datos por referencia, lo que implica que cuando igualamos una variable a otra (objeto1 = objeto2;) en realidad estamos definiendo que objeto1 apunte a la misma dirección de memoria que objeto2; de tal manera que si cambiamos una propiedad en el objeto1, esta cambiará también para el objeto2 (y viceversa).

Pero existen determinados escenarios donde necesitamos hacer una copia duplicada del objeto (clonación). Para lograrlo tenemos en .NET a nuestra disposición varias técnicas, con sus propias ventajas y desventajas. En este post pretendo comentar como lograr la clonación de la forma más sencilla (bajo mi punto de vista) aunque debo advertirte que no es la más eficiente en cuanto a consumo de recursos, pero sí la más ágil y fácil de mantener.

Posibles técnicas de clonación:

  1. Serialización y Deserialización del objeto.
  2. Implementar la interfaz IClonable para la clase.
  3. Usar MemberwiseClone() con Reflection.

Nota: De momento no se me ocurre ninguna otra técnica de clonación de objetos en .NET, si conoces alguna escríbeme un comentario para incluirla.

 

Clonar un Objeto con Serialización y Deserialización

Esta técnica de clonación de objetos .Net, consiste en:

  • Tomar el objeto que queremos clonar o duplicar, y serializarlo.
  • Tomar el resultado de la serialización y deserializarlo.
  • Almacenar la deserialización en la nueva variable.

Pero vallamos a la practica, veamos un ejemplo de como lograrlo:

//Creo el objeto de tipo Contacto
Contacto objeto1 = new Contacto { Id = 1, Nombre = "Pedro", Tel = "601010101" };
 
//Serializar objeto1 a XML
string xmlContacto = objeto1.SerializarToXml();
 
//Deserializar XML a objClonado
Contacto objClonado = xmlContacto.DeserializarTo<Contacto>();

Nota: En el código anterior hemos usado 2 métodos extensores que explicaré más adelante en este mismo artículo (SerializarToXml - DeserializarTo<T>). La clase del ejemplo (Contacto) es muy simple y es mucho mejor cualquiera de las otras 2 técnicas mencionadas, pero igual nos sirve de base para mostrar la técnica de clonación con serialización y deserialización.

Y con esto ya tenemos clonado el objeto1; a partir de este momento ya tenemos 2 variables independientes (objeto1, objClonado); actualmente ambas tienen la misma información, pero al modificar una variable no cambiará la otra automáticamente. El código lo puse en tres líneas para una mejor comprensión, también podríamos haberlo hecho así:

Contacto objeto1 = new Contacto { Id = 1, Nombre = "Pedro", Tel = "601010101" };
Contacto objClonado = objeto1.SerializarToXml().DeserializarTo<Contacto>();

 

Métodos Extensores para serialización y deserialización XML

Solo me limitaré a dejar el código de ambos métodos extensores, pues con anterioridad ya escribí un artículo donde los comentaba en profundidad Serializar y Deserializar un objeto con C#.

//Serializar a XML (UTF-16) un objeto cualquiera
public static string SerializarToXml(this object obj)
{
  try
  {
    StringWriter strWriter = new StringWriter();
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
 
    serializer.Serialize(strWriter, obj);
    string resultXml = strWriter.ToString();
    strWriter.Close();
 
    return resultXml;
  }
  catch
  {
      return string.Empty;
  }
}
 
//Deserializar un XML a un objeto T
public static T DeserializarTo<T>(this string xmlSerializado)
{
  try
  {
    XmlSerializer xmlSerz = new XmlSerializer(typeof(T));
 
    using (StringReader strReader = new StringReader(xmlSerializado))
    {
        object obj = xmlSerz.Deserialize(strReader);
        return (T)obj;
    }
  }
  catch { return default(T); }
}

Y hasta aquí el post…

 

Artículos Relacionados:

miércoles 12 de mayo de 2010

Error en SQL Server Management Studio 2008 al modificar una tabla

ErrorSQL

Este error o advertencia aparece cuando tienes instalado SQL Server Management Studio 2008 e intentas modificar una tabla de datos o alguna propiedad relacionada, al guardar los cambios aparece el mensaje:

No se permite guardar los cambios. Los cambios …”

Por suerte la solución es bien simple. En realidad el mensaje aparece porque lo tenemos configurado así, o mejor dicho, porque la instalación de SQL Server Management Studio 2008 por defecto, nos lo configuró así, pero veamos los pasos para cambiar la configuración.

 

Modificar Configuración de SQL Management Studio 2008, Permitir Guardar Cambios

  1. Ir al menú Herramientas\Opciones.
  2. Navegar hasta la opción Diseñadores\Diseñadores de tablas y bases de datos.
  3. Y en las opciones que aparecen a la derecha, DESMARCARImpedir guardar cambios que requieran volver a crear tablas”.

ErrorSQLOpciones

Y con esto ya está todo listo, ya puedes modificar cualquier tabla de datos en SQL Server Management Studio 2008.

 

Editar las 200 primeras filas en SQL Management Studio 2008

Otro tema que puede resultar incomodo en ciertas casos, es cuando pulsamos el botón derecho sobre una tabla (menú contextual), con la esperanza de editar los registros de la misma y nos encontramos con que solo nos deja:

  • Editar las primeras 200 filas.
  • Seleccionar las primeras 1000 filas.

Estas variables o cantidades también son configurables y lo que debes hacer es lo siguiente:

Modificar Configuración de SQL Management Studio 2008, Editar todas las Filas

  1. Ir al menú Herramientas\Opciones.
  2. Navegar hasta la opción Explorador de objetos de SQL Server\Comandos.
  3. Y en las opciones que aparecen en la imagen en el panel derecho, escribir un cero. Estas propiedades por defecto traerán 200 y 1000, solo bastará con escribirles el valor 0.

SQLEditarX