ClosedXML, una manera fácil de dar formato a nuestros .xlsx

closedxml

Hace ya unos meses que empezamos en este blog, con una entrada sobre ClosedXML, pero si que es cierto, que se puedo quedar un poco corta, aunque daba las ideas más básicas. Hoy, vamos a ampliar esa pequeña píldora sobre ClosedXML aprendiendo a dar formato a nuestras hojas.

Nuestro objetivo

Vamos a intentar hacer una tabla de colores como la que tenemos a continuación:

Resultado ClosedXML

Creación del proyecto

Por cambiar un poco desde de la primera parte, vamos a crear un proyecto en .NetCore (ahora que también sabemos instalar el framework en linux o como depurar sobre SSH), para ello, creamos un proyecto de consola:

consola .net core

O desde el CLI de NetCore:

dotnet new console

Lo siguiente que tenemos que hacer es añadir el paquete ClosedXML a través de nuget. Esto se puede hacer a través de la «Consola de Administrador de Paquetes» con el comando:

PM->Install-Package ClosedXML

O también desde el CLI de NetCore:

dotnet add package ClosedXML

Como siempre, utilizando el administrador que integra VS:

nuget

Generando y formateando el fichero con ClosedXML

Teniendo claro el objetivo, vamos a ponernos con en faena y analizar el código que hemos utilizado:

 
using ClosedXML.Excel;
using System.Collections.Generic;

namespace PostClosedXML2
{
  class Program
  {    
    static IEnumerable GetColors()
    {
      yield return XLColor.Red;
      yield return XLColor.Amber;
      yield return XLColor.AppleGreen;
      yield return XLColor.AtomicTangerine;
      yield return XLColor.BallBlue;
      yield return XLColor.Bittersweet;
      yield return XLColor.CalPolyPomonaGreen;
      yield return XLColor.CosmicLatte;
      yield return XLColor.DimGray;
      yield return XLColor.ZinnwalditeBrown;
    }

    static void Main(string[] args)
    {
      using (var workbook = new XLWorkbook())
      {
        //Generamos la hoja
        var worksheet = workbook.Worksheets.Add("FixedBuffer");
        //Generamos la cabecera
        worksheet.Cell("A1").Value = "Nombre";
        worksheet.Cell("B1").Value = "Color";

        //-----------Le damos el formato a la cabecera----------------
        var rango = worksheet.Range("A1:B1"); //Seleccionamos un rango
        rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
        rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
        rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; //Alineamos horizontalmente
        rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente
        rango.Style.Font.FontSize = 14; //Indicamos el tamaño de la fuente
        rango.Style.Fill.BackgroundColor = XLColor.AliceBlue; //Indicamos el color de background
        

        //-----------Genero la tabla de colores-----------
        int nRow = 2;
        foreach (var color in GetColors())
        {
          worksheet.Cell(nRow, 1).Value = color.ToString(); //Indicamos el valor en la celda nRow, 1
          worksheet.Cell(nRow, 2).Style.Fill.BackgroundColor = color; //Cambiamos el color de background de la celda nRow,2
          nRow++;
        }

        //Aplico los formatos
        rango = worksheet.Range(2, 1, nRow-1, 2); //Seleccionamos un rango
        rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
        rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
        rango.Style.Font.SetFontName("Courier New"); //Utilizo una fuente monoespacio
        rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; //Alineamos horizontalmente
        rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente


        worksheet.Columns(1, 2).AdjustToContents(); //Ajustamos el ancho de las columnas para que se muestren todos los contenidos

        workbook.SaveAs("CellFormating.xlsx");  //Guardamos el fichero
      }
    }
  }
}

Lo primero de todo, hemos creado una lista con los colores que queremos utilizar para nuestra tabla. Para ello, utilizamos los colores propios del paquete, que trae una lista enorme de colores:

 
static IEnumerable GetColors()
{
  yield return XLColor.Red;
  yield return XLColor.Amber;
  yield return XLColor.AppleGreen;
  yield return XLColor.AtomicTangerine;
  yield return XLColor.BallBlue;
  yield return XLColor.Bittersweet;
  yield return XLColor.CalPolyPomonaGreen;
  yield return XLColor.CosmicLatte;
  yield return XLColor.DimGray;
  yield return XLColor.ZinnwalditeBrown;
}

Una vez que tenemos eso controlado, vamos a entrar al jugo del código. En primero lugar, podemos ver que todo el código esta dentro de un using:

 
using (var workbook = new XLWorkbook())
{
   //Código
}

Con esto conseguimos que los recursos utilizados para generar el fichero se liberen correctamente al acabar de usarlos. Lo siguiente que vemos, es como generamos la hoja dentro del libro:

 
//Generamos la hoja
var worksheet = workbook.Worksheets.Add("FixedBuffer");

Una vez que tenemos la hoja creada, añadimos las dos primeras celdas que nos servirán de cabecera para la tabla:

 
//Generamos la cabecera
worksheet.Cell("A1").Value = "Nombre";
worksheet.Cell("B1").Value = "Color";

Vamos a darle formato a la cabecera de la tabla:

 
//-----------Le damos el formato a la cabecera----------------
var rango = worksheet.Range("A1:B1"); //Seleccionamos un rango
rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; //Alineamos horizontalmente
rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente
rango.Style.Font.FontSize = 14; //Indicamos el tamaño de la fuente
rango.Style.Fill.BackgroundColor = XLColor.AliceBlue; //Indicamos el color de background

Para trabajar con mayor comodidad, seleccionamos un rango (A1:B1), de modo que todo lo que hagamos sobre el rango, se va a aplicar a todas las celdas del rango, en este caso a A1 y a B1. Lo que hacemos es asignarle los bordes extreriores e interiores, alinear el contenido horizontal y verticalemnte, le modificamos el tamaño de la fuente, y por ultimo, pintamos el color de fondo. Sin ningun problema, generamos la tabla de colores:

 

//-----------Genero la tabla de colores-----------
int nRow = 2;
foreach (var color in GetColors())
{
    worksheet.Cell(nRow, 1).Value = color.ToString(); //Indicamos el valor en la celda nRow, 1
    worksheet.Cell(nRow, 2).Style.Fill.BackgroundColor = color; //Cambiamos el color de background de la celda nRow,2
    nRow++;
}

Como en casos anteriores, asignamos un valor a una celda, y un backcolor a la otra. Con esto, solo nos queda aplicar los formatos y guardar. Vamos a aplicar los formatos:

 
//Aplico los formatos
    rango = worksheet.Range(2, 1, nRow-1, 2); //Seleccionamos un rango
    rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
    rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
    rango.Style.Font.SetFontName("Courier New"); //Utilizo una fuente monoespacio
    rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; //Alineamos horizontalmente
    rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente

Pero ojo, esta vez, hemos asignado también la fuente:

 
rango.Style.Font.SetFontName("Courier New");

Esto lo hacemos para que la tabla nos quede perfectamente cuadrada al utilizar letras monoespacio. Por ultimo, queremos que las celdas se queden perfectamente a la vista todas, aunque el contenido sea mayor que el ancho de la columna, por lo tanto, vamos a ajustar el ancho de columnas. Eso lo hacemos con:

 
worksheet.Columns(1, 2).AdjustToContents(); //Ajustamos el ancho de las columnas para que se muestren todos los contenidos

Lo que conseguimos así, es que el ancho de las columnas 1 y 2, se ajuste de modo que se vea el contenido de todas las celdas. Con todo hecho, simplemente guardamos:

 
workbook.SaveAs("CellFormating.xlsx");  //Guardamos el fichero

Y al abrir el excel, veremos que se nos ha quedado una tabla como la que presentábamos al principio. Como siempre, si queréis probar el código fuente, os dejo el enlace al repositorio de GitHub. Esto solo es una pequeña pincelada de todo los que se puede conseguir con ClosedXML y con OpenXML en general. En futuras entradas, seguiremos ampliando su uso.

Depuración remota sobre SSH

      No hay comentarios en Depuración remota sobre SSH

Depuración remota sobre SSHDespués de la entrada sobre como instalar NetCore en Linux (o sobre cualquier otro entorno), el siguiente paso lógico es poder depurar nuestro código mientras corre en Linux, como lo haríamos sobre Windows.

Para esto, tenemos 2 opciones, utilizar Visual Studio Code o Visual Studio para hacer depuración remota sobre ssh,. En este caso, vamos a utilizar la segunda opción, ya que en la mayoría de los casos en los que usemos NetCore, correrá en un servidor sin interfaz gráfica.

Para ello, lo primero que necesitamos es que nuestro equipo Linux tenga un servidor SSH habilitado, esto es lo que ocurre habitualmente, pero en caso de no haberlo puesto durante la instalación del OS, se puede añadir sin problema.

Una vez dicho esto, vamos con ello.

Proyecto

Para poder seguir la entrada, lo primero que vamos a hacer es crear un proyecto de consola de NetCore:

consola .net core

Al que le vamos a poner este código:

 
using System;
using System.Threading;

namespace PostDepuracionRemota
{
    class Program
    {
        static void Main(string[] args)
        {
            int nIteraciones = 100;
            Console.WriteLine($"El programa añadirá {nIteraciones} lineas de consola, con una espera de 1 segundo entre lineas");
            for(int i = 0; i < nIteraciones; i++)
            {
                Console.WriteLine(DateTime.Now);
                Thread.Sleep(1000);
            }
        }
    }
}

Es un código muy simple, ya que la finalidad es probar la  depuración remota sobre SSH, simplemente, ejecutara 100 veces el Console.WriteLine, mostrando por pantalla la hora en la que estamos. Con esto, vamos a ganar el tiempo que necesitamos para asociarnos al proceso remoto. Si lo ejecutamos tal cual, tendremos una salida parecida a esta:

Ejemplo depuración remota

Una vez que tenemos esto, lo colocamos en nuestro servidor, y vamos al lío!!!

Depuración remota sobre SSH

Visual Studio 2017 añade varias opciones para asociarnos a un proceso en ejecución, para ello, desde el menú "Depurar", vamos a la opción "Asociar al proceso...", o pulsamos el atajo "Ctrl+Alt+P"

Asociar al proceso

Eso, nos va a mostrar una nueva ventana:

VentanaAsociar

En ella, seleccionamos el tipo de conexión SSH y ponemos la dirección del servidor. Con eso, al pulsar actualizar, se nos mostrará una nueva ventana para pedirnos los datos de conexión:

ventanaDatosSSH

Basta con que rellenemos los campos con los valores de conexión a nuestro servidor, y acto seguido,  (igual hay que pulsar sobre actualizar) se nos mostraran los procesos activos en el servido:

ProcesosActivos

Vamos a utilizar la opción de filtro, para buscar los procesos "dotnet":

filtro

Seleccionamos el proceso que queremos depurar, y esto nos lanza una ultimo ventana, en la que nos pide que le indiquemos como queremos depurar:

Modo

Tenemos que seleccionar "Managed". Al seleccionar el proceso, vemos que se asocia a la ejecución, y nos permite depurar el ejecutable de manera remota sobre ssh:

Breakpoint

Aclaraciones

En caso de necesitar instalar componentes, Visual Studio se encarga de descargarlos e instalarlos sin necesitar nada por nuestra parte. Esto es así siempre, salvo que nos falten paquetes que se consideran básicos, como pueden ser el servidor SSH, curl o wget, o unzip. En caso de que nos falte alguno o todos ellos,  debemos instalarlos nosotros, o cuando intentemos asociarnos se mostrara un error parecido a este:

Error Paquetes

/home/username/.vs-debugger/GetVsDbg.sh -v vs2017u5 -l "/home/username/.vs-debugger/vs2017u5"

Esto se soluciona fácilmente instalando todo lo que nos falte con el comando:

sudo apt-get install openssh-server unzip curl

Espero que haya sido de utilidad, aunque le daremos uso en siguientes entradas cuando creemos DLL de C++ y las consumamos en NetCore, para poder comprobar en caso de que tengamos algún problema.

Como instalar .NetCore en Linux

      No hay comentarios en Como instalar .NetCore en Linux

.NetCore en Linux

Después de tantas entradas hablando sobre .NetCore y lo que me gusta utilizar una herramienta multiplataforma, hoy vamos a ver como instalar el SDK de .NetCore en Linux. Esto puede parecer algo complicado, pero en realidad es muy muy fácil. En este caso, vamos a utilizar para el ejemplo una distribución Debian 9.5.

Instalando .NetCore en Linux

En primer lugar, es necesario instalar el paquete «apt-transport-https», el cual nos permite conectar con los repositorios de Microsoft:

sudo apt-get install apt-transport-https

Después, vamos a registrar las claves de Microsoft dentro de el registro de claves seguras, de cara a que no nos de advertencias al utilizar HTTPS los repositorios, para ello, escribimos las siguientes instrucciones en la terminal (En caso de no utilizar Debian sino otra distro, puedes consultar las instrucciones aquí):

wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg
sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
wget -q https://packages.microsoft.com/config/debian/9/prod.list
sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list

Una vez hecho esto, ya hemos añadido los repositorios a nuestra maquina, con lo cual, solo nos queda actualizar la lista e instalar el SDK:

sudo apt-get update
sudo apt-get install dotnet-sdk-2.1

Con estos sencillos pasos, ya tenemos el SDK instalado en nuestro equipo con Debian, y podemos empezar a trabajar con el.

Probando el SDK

Una vez tenemos el SDK instalado, vamos a comprobar que todo funciona correctamente, para ello, vamos a descargar el proyecto de las entrada Venciendo el miedo a las pruebas unitarias en .Net , pero también podríamos hacerla con Rompiendo limites: Mocking en las Pruebas Unitarias .Net o cualquiera de las que usan .NetCore.

*NOTA: Voy a asumir que no todo el mundo usa git, por los que utilizaré los enlaces https, en caso de hacerlo con git, simplemente seria necesario hacer un «git clone» en vez de una descarga wget.

Vamos con el primero, lo primero, es descargarlo, descomprimirlo y entrar al proyecto:

wget https://github.com/JorTurFer/PostPruebasUnitariasCore/archive/master.zip
unzip -a master.zip
cd PostPruebasUnitariasCore-master

Una vez dentro de la carpeta, vamos a construir el proyecto con:

dotnet build *.sln

Si todo va bien, veremos algo como esto:

build result

Y vamos a comprobar que las pruebas unitarias se ejecutan correctamente accediendo a ellas y ejecutándolas con:

cd PruebasUnitarias
dotnet test *.csproj

Lo que nos debería mostrar algo como esto:

test result

En próximas entradas, mostraremos como depurar sobre SSH en linux o como instalar nuestros programas como servicio .NetCore en Linux.