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"%>

13 de junio de 2010

Enum, Attribute To List

Hace unos meses atrás escribí un artículo inicial sobre Enumeraciones y algunos ejemplos básicos. Hoy pretendo continuar aquel post, y veremos los siguientes aspectos:

  1. Usar atributos en Enumeraciones.
  2. Método para recuperar el atributo de un determinado valor de la enumeración (GetDescripcion).
  3. Método para recuperar una lista de todos los elementos de la Enumeración (GetValoresDescripciones).

El objetivo de ambos métodos extensores es poder hacer lo siguiente:

string descripcion = TipoDocumento.Dni.GetDescripcion();

var lstEnumVals = typeof(TipoDocumento).GetValoresDescripciones();

Enum 2 List

Usar Enumeración con Attribute

enum TipoDocumento
{
    [Descripcion("Documento Nacional de Identidad")]
    DNI, // 0

   

    [Descripcion("Número de Identificación de Extranjeros")]

    NIE, // 1

   
    Pasaporte, // 2
   
    [Descripcion("Otros Documentos")]
    Otro = 99
};

Nota: El tipo predeterminado subyacente de las enumeraciones es el int y el primer enumerador tiene valor 0, incrementándose sucesivamente en 1 (A menos que definamos otra cosa).

La enumeración definida, está usando un atributo (Descripcion) que debemos definir en una clase (DescripcionAttribute) como veremos a continuación:

public class DescripcionAttribute : Attribute

{

  public string Descripcion { get; set; } 

  public DescripcionAttribute(string descripcion)

  {

    Descripcion = descripcion;

  }

}

 

Recuperar Attribute de un elemento Enum

public static string GetDescripcion(this Enum valor)

{

  Type type = valor.GetType();

  FieldInfo fieldInfo = type.GetField(valor.ToString());

  var attribs = fieldInfo.GetCustomAttributes(

                  typeof(DescripcionAttribute), false) as DescripcionAttribute[];

  return (attribs == null || attribs.Length == 0) ?

          valor.ToString() : attribs[0].Descripcion;

}

 

Recuperar todos los elementos de una Enum

public static List<KeyValuePair<string, string>> GetValoresDescripciones(

  this Type enumType)

{

  var arrValores = Enum.GetValues(enumType);

  var lstEnumDescripcion = new List<KeyValuePair<string, string>>();

 

  foreach (var valor in arrValores)

  {

    FieldInfo fieldInfo = enumType.GetField(valor.ToString());

   

    var attribs = fieldInfo.GetCustomAttributes(

                    typeof(DescripcionAttribute), false) as DescripcionAttribute[];

    var descripcion = (attribs == null || attribs.Length == 0) ?

                       valor.ToString() : attribs[0].Descripcion;

    lstEnumDescripcion.Add(

      new KeyValuePair<string, string>(valor.GetHashCode().ToString(), descripcion));

  }

  return lstEnumDescripcion;

}

O si prefieres crear el mismo método, pero remplazando el foreach por expresiones LINQ entonces:

public static List<KeyValuePair<string, string>> GetValoresDescripciones(

  this Type enumType)

{

  var arrValores = Enum.GetValues(enumType);

 

  return (from object valor in arrValores

          let fieldInfo = enumType.GetField(valor.ToString())

          let attribs = fieldInfo.GetCustomAttributes(typeof (DescripcionAttribute), false)

                        as DescripcionAttribute[]

          let descripcion = (attribs == null || attribs.Length == 0) ?

                             valor.ToString() : attribs[0].Descripcion

          select new KeyValuePair<string, string>(

                       valor.GetHashCode().ToString(), descripcion)).ToList();

}


Artículos Relacionados:

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:

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í.

Para Visual Studio 2012 y 2013

Podrás descargarte los diferentes Packages de Crystal Reports para VS 2012 o VS 2013

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: