miércoles, 11 de julio de 2012

ASP.NET + jqGrid + Exportación Excel


Hola.
Para tratar la exportación de los datos del jqGrid a Excel, vamos a partir del proyecto que generamos en el anterior tutorial sobre jqGrid.
Lo primero que vamos a hacer es crear una Clase que imulará el suministro de datos desde la base de datos. Así pues crearemos una nueva carpeta “Controller”en nuestro proyecto , y dentro de esta carpeta agregaremos una nueva clase a la que llamaremos “PagosController”.
En el proyecto anterior ya habíamos creado dentro del webservice un código que generaba los datos suministrados por nuestra supuesta Base de datos, así pues lo que haremos a continuación es mover ese código del web service a la clase que hemos creado y hacer que el WebService solicite esta información a dicha clase y que continúe funcionando como hasta ahora.
Así pues moveremos del WebService el siguiente bloque de código:

List<Pago> data = new List<Pago>();
Random rnd = new Random();
for (int n = 0; n < 30; n++)
{
  int num_days = rnd.Next(-365, -30);
  DateTime fecha = DateTime.Today.AddDays(num_days);
  decimal importe = Math.Round(Convert.ToDecimal((rnd.NextDouble() * 1000)), 2);
  decimal tasa = Math.Round(Convert.ToDecimal((rnd.NextDouble() * 100)), 2);
  decimal total = Math.Round((importe + tasa), 2);
  data.Add(new Pago()
  {
    ID = n + 1,
    FechaPago = fecha,
    Concepto = "JOHN DOE " + (n + 1).ToString(),
    Importe = importe,
    Tasas = tasa,
    Total = total,
    Notas = "Nota " + (n + 1).ToString()
  });
}

Y crearemos en la clase “PagosController” el siguiente método con el código movido:

public static List<Pago> GetListaPagos()
{
  List<Pago> data = new List<Pago>();
  Random rnd = new Random();
  for (int n = 0; n < 30; n++)
  {
    int num_days = rnd.Next(-365, -30);
    DateTime fecha = DateTime.Today.AddDays(num_days);
    decimal importe = Math.Round(Convert.ToDecimal((rnd.NextDouble() * 1000)), 2);
    decimal tasa = Math.Round(Convert.ToDecimal((rnd.NextDouble() * 100)), 2);
    decimal total = Math.Round((importe + tasa), 2);
    data.Add(new Pago()
    {
      ID = n + 1,
      FechaPago = fecha,
      Concepto = "JOHN DOE " + (n + 1).ToString(),
      Importe = importe,
      Tasas = tasa,
      Total = total,
      Notas = "Nota " + (n + 1).ToString()
    });
  }
  return data;
}

Por último haremos que el webservice llame a este método para solicitar la información

List<Pago> data = Controller.PagosController.GetListaPagos();

De esta forma el WebService se comporta igual y ahora podemos llamar a GetListaPagos desde otros puntos de la solución.
En este punto, antes de continuar, podríais ejecutar la solución para aseguraros que la página del grid continua funcionando como hasta ahora.
Ahora vamos a hacer es generar una Pagina aspx, la cual va a recibir las distintas peticiones de exportación y se encargará de recoger los datos y exportarlos a Excel.
Así pues crearemos una nueva página a la que llamaremos “Export2Excel.aspx”.
La idea en esta página es llamar el método del controlador que nos proporciona los datos a exportar. Convertir la lista de Pagos en un DataTable y retornar el data table exportado a Excel.
Para realizar estas acciones, lo primero que vamos a generar es un conjunto de métodos que nos permitirán convertir nuestras listas genéricas en Datatables. Creamos el siguiente código en nuestra página:

public static DataTable ConvertTo<T>(IList<T> list)
{
  DataTable table = CreateTable<T>();
  Type entityType = typeof(T);
  PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
  foreach (T item in list)
  {
    DataRow row = table.NewRow();
    foreach (PropertyDescriptor prop in properties)
    {
      row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
    }
    table.Rows.Add(row);
  }
  return table;
}
public static DataTable CreateTable<T>()
{
  Type entityType = typeof(T);
  DataTable table = new DataTable(entityType.Name);
  PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
  foreach (PropertyDescriptor prop in properties)
  {
    // HERE IS WHERE THE ERROR IS THROWN FOR NULLABLE TYPES
    table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
  }
  return table;
}

Con los métodos creados, vamos a proceder a crear una función que se encargue de generar la respuesta en formato Excel a partir de un Datatable. Así pues, creamos el siguiente código:

public static void ExportToExcel(string fileName, DataTable dt)
{
  HttpContext.Current.Response.Clear();
  HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}", fileName));
  HttpContext.Current.Response.ContentType = "application/ms-excel";
  string tab = "";
  foreach (DataColumn dc in dt.Columns)
  {
    HttpContext.Current.Response.Write(tab + dc.ColumnName);
    tab = "\t";
  }
  HttpContext.Current.Response.Write("\n");
  int i;
  foreach (DataRow dr in dt.Rows)
  {
    tab = "";
    for (i = 0; i < dt.Columns.Count; i++)
    {
      HttpContext.Current.Response.Write(tab + dr[i].ToString());
      tab = "\t";
    }
    HttpContext.Current.Response.Write("\n");
  }
  HttpContext.Current.Response.End();
}

Ya tenemos todos los elementos que necesitamos para la exportación.
Solo nos falta unificar todos estos puntos en el Page_Load de la página:

protected void Page_Load(object sender, EventArgs e)
{
  List<Pago> data = Controller.PagosController.GetListaPagos();
  DataTable dt = ConvertTo(data);
  ExportToExcel("ListaPagos.xls", dt);
}

Ya tenemos nuestra página de exportación a Excel lista para ser invocada.
Vamos ahora a enlazar nuestro jqGrid con esta página.
Para ello vamos a agregar al jqGrid un botón que al ser pulsado invocara nuestra página.
Asi el código de nuestro jqGrid quedará de la siguiente forma.

jQuery(document).ready(function () {
  $("#contactsList").jqGrid({
    url: '/WsDataProvider.asmx/GetGridDataOrder',
    datatype: 'json',
    mtype: 'POST',
    ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
    serializeGridData: function (postData) {
      return JSON.stringify(postData);
    },
    jsonReader: { repeatitems: false, root: "d.rows", page: "d.page", total: "d.total", records: "d.records" },
    colModel: [
      { name: 'ID', label: 'ID', key: true, width: 60, sortable: true, align: "center", hidden: false },
      { name: 'FechaPago', label: 'Fecha', width: 80, sortable: true, hidden: false, formatter: 'date', formatoptions: { srcformat: 'm/d/Y h:i:s', newformat: 'd-m-Y'} },
      { name: 'Concepto', label: 'Concepto', width: 180, sortable: true, hidden: false },
      { name: 'Importe', label: 'Importe', width: 180, sortable: true, align: "center", hidden: false, formatter:currencyFmatter },
      { name: 'Tasas', label: 'Tasa', key: true, width: 60, sortable: true, align: "center", hidden: false, formatter: currencyFmatter },
      { name: 'Total', label: 'Total', width: 80, sortable: true, align: "center", hidden: false, formatter: currencyFmatter },
      { name: 'Notas', label: 'Notas', width: 180, sortable: false, hidden: false }
    ],
    rowNum: 10,
    rowList: [10, 20, 30],
    pager: "#gridpager",
    viewrecords: true,
    gridview: true,
    rownumbers: true,
    height: 420, width: 980,
    caption: 'Lista de Pagos'
  }).jqGrid('navGrid', '#gridpager', {
    edit: true, add: true, del: false, search: true
  }).jqGrid('navButtonAdd', '#gridpager', {
    caption: '<span class="ui-pg-button-text">Export</span>',
    buttonicon: "ui-icon-extlink",
    title: "Export To Excel",
    onClickButton: function () {
      window.location = 'Export2Excel.aspx';
    }
  });
});

He marcado en gris el código que se encarga de generar el botón de exportación.
Pues ya solo nos falta probarlo.
Ya tenemos nuestro jqGrid con exportación de datos a Excel.
Como siempre, teneis a vuestra disposición el proyecto para que lo estudieis
Espero que os sea de ayuda, a partir de aquí podéis sofisticar el sistema como queráis.
Saludos.-

No hay comentarios:

Publicar un comentario