Tuesday, December 14, 2010

Reportes PDF en ASP.NET MVC como contenido inline

Este post nace a partir de una inquietud de una entrada anterior. Cómo mostrar un reporte PDF hecho en la librería Report.net dentro de una página como un objeto mbebido.

Esto es bastante sencillo si usamos un iframe como repositorio de nuestro reporte de la siguiente manera.
  • Creamos un proyecto ASP.NET MVC
  • Realizamos los pasos necesarios para crear un reporte con Report.net
  • Dentro de nuestra página Home/Index.aspx creamos pegamos el código:






Inline example


< iframe id="HelloWorld" runat="server"
src="home/HelloWorld"
height="500" scrolling="AUTO" width="600"> < /iframe >



El resultado final:

Espero pueda ayudar a los que buscaban esta característica.

Sunday, October 04, 2009

Crear Reportes PDF con ASP.NET MVC


Estos días estaba leyendo el libro Professional ASP.NET MVC 1.0 de wrox y creía que este artículo posiblemente será muy útil para aquellos que comienzan con este alucinante framework implementando el patrón Model-View-Controller y no tienen la ayuda de third parties que les generen reportes (Yo nunca fui muy amigo de Crystal Reports, así que preferí otras opciones) o que simplemente quieran usar un proyecto open source. Usualmente, necesitaremos mostrar nuestra información en un formato manejable, elegante y liviano, por lo que utilizaremos la librería Report.net que nos genera reportes PDF mediante puro código. Para aquellos que no conocen su uso, pueden ver mis posts previos.
Esencialmente, la API de la librería arma la estructura de un documento PDF y renderiza el resultado en la página web con un content-Type de tipo application/pdf.


Este artículo se divide en dos:


  • La modificación del proyecto Report que viene con el download de la librería para permitir la generación del reporte en MVC

  • La creación de un proyecto ASP.NET MVC con un reporte de ejemplo

Comencemos. Al momento de escribir este artículo, la librería no soportaba la generación del reporte en MVC, por lo que tuve que hacer una pequeña modificación al mismo. En el transcurso de los días trataré de incluir esto a la librería. Primeramente debemos descargar el proyecto de Report.net de sourceforge. Abrimos el mismo en VS.

Veremos la estructura de toda la librería. Aquí el archivo que nos interesa es el archivo Report.cs que se encuentra en la superficie del proyecto. Lo abrimos y buscamos el método:


public static void ResponsePDF(Report report, System.Web.UI.Page page)


Aquí explico un poco. Este método es utilizado para poder generar el reporte en pantalla. Para ello, tiene como parámetros de entrada un objeto Root.Reports.Report y un System.Web.UI.Page.



La entidad Report será utilizada para llamar al método Create que implementa cualquier reporte que creemos heredando de la misma Root.Reports.Report.


La página es solamente utilizada para acceder al objeto Response, que es el que modela la respuesta del servidor a la página. En este tenemos los elementos necesarios para mostrar un output en la página resultante. Aquí podemos ver que se limpia el contenido anterior, se hace el set del contentType a application/pdf, se crea el reporte cargando el OutputStream de la página y llamándose a End del objeto response.


Mi aporte consiste en adicionar un nuevo método que llamé:

public static void ResponsePDF4MVC(Report report, System.Web.HttpContext currentContext)



public static void ResponsePDF4MVC(Report report, System.Web.HttpContext currentContext)
{
currentContext.Response.Clear();
currentContext.Response.ContentType = "application/pdf";

if (!(report.formatter is PdfFormatter))
{
throw new ReportException("PDF formatter required");
}
if (report.page_Cur == null)
{
report.Create();
}

report.formatter.Create(report, currentContext.Response.OutputStream);
currentContext.Response.End();
}

Ya desde aquí, vemos que la firma cambió. En vez de utilizar un objeto System.Web.UI.Page, usaremos un HttpContext. Debido a que ASP.NET MVC no maneja ninguna Page e interactúa directamente con los HttpHandlers (MvcHandler) . Esto nos da la posibilidad de hacer lo que deseemos con el output resultante. Tal como en el bloque anterior, este método utiliza el parámetro tipo HttpContext para manejar su objeto Response. Por lo demás, el manejo del método es igual a su padre :D.


Compilamos el proyecto y tendremos nuestro assembly modificado.


Bien, ya tenemos lo necesario para crear nuestro primer reporte ASP.NET MVC. Antes de continuar, será necesario que revisemos si tenemos ASP.NET MVC instalado para continuar. Si no lo tenemos, podremos descargarlo desde el sitio de asp.net.

Una vez sepamos que podemos continuar, abriremos Visual Studio y creamos un proyecto ASP.NET MVC (File -> New -> Project)


Nombramos a nuestro proyecto como PDFGenerator y definimos la ruta a grabar. Lo siguiente que veremos será la pantalla preguntándonos si queremos crear pruebas unitarias. Para efectos de este ejemplo, seleccionaremos la opción No, do not create a unit test Project.



A continuación, tendremos un proyecto ASP.NET MVC inicial generado para nosotros.



Haremos referencia a nuestro assembly Reports.dll

Ahora, iremos por partes. Primero el Modelo, luego el Controller y finalmente la vista.


Model

Conceptualmente, el modelo define la estructura de nuestros datos, las reglas y la lógica de negocio. Es aquí donde crearemos nuestro objeto reporte, el mismo tendrá toda la estructura a ser mostrada en pantalla posteriormente.

Sobre la carpeta Models creamos una nueva clase a la que llamaremos SampleReport. Éste debe heredar de Root.Reports.Report.



public class SampleReport : Report

No olvidemos añadir la referencia a
using Root.Reports;

Bueno, ahora voy a armar un reporte simple, por lo que mi código terminaría así:

public class SampleReport : Report
{
FontDef _fontDefinition;
FontProp _fontProperty;

protected override void Create()
{
// Este llamado es muy importante para generar la página
NewPage();
// Inicialia las propiedades del reporte
InitializeReportProperties();
// Imprime mensaje
PrintHelloWorldMessage();
}

private void InitializeReportProperties()
{
// Este estilo de fuente debe ser definido sólo una vez
_fontDefinition = new FontDef(this, FontDef.StandardFont.TimesRoman);
_fontProperty = new FontProp(_fontDefinition, 10, Color.Navy);
}

private void PrintHelloWorldMessage()
{
page_Cur.AddCT_MM(100, 50, new RepString(_fontProperty, "Good morning joy!"));

page_Cur.AddCT_MM(100, 70, new RepString(_fontProperty, "Implementing ASP.NET MVC"));
}
internal void NewPage()
{
new Root.Reports.Page(this);
}

}

Explicación:

Hacemos un Override del método Create, esto nos permitirá tener el punto de partida para crear el reporte. El método NewPage nos permite crear una nueva página. Sí o sí tendremos que hacer esta llamada. Inicializamos las propiedades del reporte con InitializeReportProperties y finalmente imprimimos nuestro mensaje: “Buen día alegría!” :D.
Una vez que hemos definido el reporte eso es todo con relación a la vista.


Controller

La parte de controller es mucho más sencilla, ya que casi todo el trabajo ha sido hecho. Lo único que tendremos que hacer será añadir un método público denominado HelloWorld en nuestro HomeController. Ésta será tomada como acción y accedida desde la URL.
Dentro de la acción, instanciaremos nuestro reporte y haremos la llamada al método ResponsePDF4MVC (el que previamente creamos en el proyecto Report). Quedaría así:


public ActionResult HelloWorld()
{
SampleReport report = new SampleReport();
RT.ResponsePDF4MVC(report, this.HttpContext.ApplicationInstance.Context);

return View();
}

Notemos que la llamada a ResponsePDF4MVC tiene como parámetro el contexto de ApplicationInstance, ya que this.HttpContext es una implementación especial de tipo HttpContextBase. Hacemos la llamada a la vista y eso es todo en nuestro controller.

View

En esta parte, añadiremos una vista llamada HelloWorld.aspx bajo la carpeta Views/Home:


Esta página me sirve para hacer el llamado a la acción, el sistema de ruteo haga la llamada al controller identificando la acción HelloWorld y éste a su vez devuelva el resultado a una vista con el mismo nombre. Es importante el nombrado de views y acciones, esto por convención, nos permitirá hacer la comunicación entre los elementos del patrón.

Ya casi acabando, modificaremos la página Index.aspx, eliminamos el contenido de MainContent por con un simple link que apunte a nuestro HelloWorld.aspx. Entonces nuestra página index.aspx quedaría así:



<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>


<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>My first ASP.NET MVC PDF</h2>
<p>
Watch our <%= Html.ActionLink("Hello world", "HelloWorld") %> example
</p>

</asp:Content>


Si nos fijamos en el código que tiene el llamado a ActionLink, veremos que vamos a mostrar solamente el texto Hello world acompañado de la acción a ser invocada. Por dentro, el sistema de ruteo se encargará de llamar al método HelloWorld y nuestro controller sabrá que tiene que existir una página también llamada HelloWorld.aspx.

Finalmente, compilamos nuestro código le damos debug (dejamos que se pueda modificar el archivo web.config para hacer debugging) para ver nuestra página de la siguiente manera:


Presionando sobre el link Hello world tendremos finalmente nuestro tan ansiado reporte PDF en ASP.NET MVC



Bueno, eso es todo amigos. Mi primer reporte PDF en ASP.NET MVC implicó que conozca la API de reporte Report.net, también implicó el conocimiento de conceptos del patrón MVC y la práctica con ASP.NET MVC para juntar todo. En sí no es complicado. Como lo dije antes, el construir el reporte “a mano” puede ser un poco largo para quienes están acostumbrados a usar herramientas tipo Crystal, pero si lo vemos del otro lado tendremos una libertad completa para generar contenido en PDF mediante código, sin mencionar que en vez de usar DataTables, podremos actuar directamente con entidades de negocio.

ASP.NET MVC puede ser asimilado rápidamente, la página del framework tiene excelentes artículos para comenzar a aprender y también está la opción de adquirir un libro que hable del tema. Yo recomendaría el libro Professional ASP.NET MVC 1.0, escrito por la gente que diseñó el framework. También está ASP.NET MVC In Action que basa la explicación del modelo en base a Domain Driven Development.

Este ejemplo lo realicé porque se me vino una corazonada una de esas noches de inspiración. Si es que existen algunas inconsistencias conceptuales, les agradezco si pueden comentar al respecto.

Bueno, eso es todo. Espero que esto sirva para complementar a este maravilloso framework MVC y ayudar a quienes lo necesitan.

Sunday, June 29, 2008

Reportes PDF con Report.net - Creación de saltos de página

En esta ocasión voy a explicar cómo realizar un reporte de varias páginas utilizando la librería Report.net (librería gratuita que genera reportes PDF para asp.net) mediante el uso de una variable a que denominé cursor.

Primero deberemos descargar la librería que contiene al assemblie Reports.dll y hacer referencia a los proyectos en los que se utilizarán los reportes.

Para mantener ordenado el código, he creado un proyecto llamado Reportes en el cual tengo la clase ReporteCursor y además creé un proyecto web que hace referencia al anterior y contiene una página llamada Cursor1.aspx.

La clase ReporteCursor hereda de Report propia del namespace Root.Reports. Debido a que todos los elementos del reporte deben ser declarados, y no tenemos una forma automática de hacer saltos de página vamos a declarar la variable cursorActual de tipo double que se irá incrementando cada vez que adicionemos una fila de texto en nuestro reporte. Antes de cada adición de un texto verificaré si el cursor ha sobrepasado el límite de la página también declarada como variable de clase.

Tenemos un override del método Create que realiza todo el trabajo de creación y armado del reporte.

Dentro de Create tenemos tres métodos

  • InicializarReporte() -> Crea una nueva página e inicializa las propiedades de fuentes

  • ProbarSaltoCursor() -> Imprime líneas de texto en el reporte y realiza saltos de página si es necesario

  • CrearPieDePagina() -> Muestra el texto de # de página y total de páginas


A continuación explicaré el método ProbarSaltoCursor. Primero inicializa la variable cursorActual con el valor del margen superior (rPosTop) y mediante una instrucción for que va de 1 a 100 haré el llamado al método CrearLineaDeTexto la misma que realiza el despliegue del texto en la página.


private void ProbarSaltoCursor()
{
// Se inicializa el cursor al valor predeterminado
IniciarCursor();
// Se va a llamar al salto de cursor dentro de un bucle 100 veces
for (int index = 1; index <= 100; index++) CrearLineaDeTexto(string.Format("Imprimiendo linea Nº : {0:00}", index)); }


Dentro del método CrearLineaDeTexto tenemos un método que revisa si el cursor ya ha sobrepasado el límite inferior, si es así se crea una nueva página. Se adiciona el texto que queremos que aparezca en la posición x = 100; y = cursorActual e incrementamos el cursor en 10 unidades.


private void CrearLineaDeTexto(string pTexto)
{
// Primero revisamos si el cursor ha revasado el limite de la pagina
EvaluarSaltoPagina();
// Se adiciona a la pagina el texto en una posicion predeterminada
page_Cur.AddCT_MM(100, cursorActual, new RepString(_propiedadFuente, pTexto));
cursorActual += 10;
}


Concluyendo el método Create tenemos al método CrearPieDePagina que nos imprimirá el número de página y total de páginas en la parte inferior derecha de cada una.

Finalmente en el code-behind de la página Cursor1.aspx tendremos el siguiente código
Archivo.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
ReporteCursor reporte = new ReporteCursor();
RT.ResponsePDF(reporte, this);
}


ReporteCursor.cs

using System;
using System.Collections.Generic;
using System.Text;
using Root.Reports;
using System.Drawing;

namespace Reportes
{
public class ReporteCursor : Report
{
#region Propiedades reporte

FontDef _definicionFuente;
FontProp _propiedadFuente;
FontProp _propiedadFuentePequenia;
FontProp _propiedadFuenteFooter;

// Se definen los bordes de la pagina
internal Double rPosTop = 25;
internal Double rPosBottom = 280;
internal Double rPosLeft = 10;
internal Double rPosRight = 200;

// se define una variable que represente un cursor
double cursorActual;

#endregion

protected override void Create()
{
InicializarReporte();
ProbarSaltoCursor();
CrearPieDePagina();
}

private void ProbarSaltoCursor()
{
// Se inicializa el cursor al valor predeterminado
IniciarCursor();
// Se va a llamar al salto de cursor dentro de un bucle 100 veces
for (int index = 1; index <= 100; index++) CrearLineaDeTexto(string.Format("Imprimiendo linea Nº : {0:00}", index)); } #region Métodos básicos private void CrearPieDePagina() { foreach (Root.Reports.Page page in enum_Page) page.AddRT_MM(rPosRight, rPosBottom + 4, new RepString(_propiedadFuenteFooter, string.Format("Página {0} de {1}", page.iPageNo, iPageCount))); } private void EvaluarSaltoPagina() { if (cursorActual > rPosBottom)
{
IniciarCursor();
NuevaPagina();

page_Cur.AddCT_MM(20, 10, new RepString(_propiedadFuentePequenia, "(Nueva página)"));
}
}
private void InicializarReporte()
{
NuevaPagina();
InicializarPropiedadesReporte();
}
private void InicializarPropiedadesReporte()
{
// Este estilo de fuente debe ser definido sólo una vez
_definicionFuente = new FontDef(this, FontDef.StandardFont.TimesRoman);
_propiedadFuente = new FontProp(_definicionFuente, 10, Color.Navy);
_propiedadFuentePequenia = new FontProp(_definicionFuente, 7, Color.Maroon);
_propiedadFuenteFooter = new FontProp(_definicionFuente, 5, Color.SlateBlue);
}
internal void NuevaPagina()
{
new Root.Reports.Page(this);
}

#endregion

#region Metodos especificos

private void CrearLineaDeTexto(string pTexto)
{
// Primero revisamos si el cursor ha revasado el limite de la pagina
EvaluarSaltoPagina();
// Se adiciona a la pagina el texto en una posicion predeterminada
page_Cur.AddCT_MM(100, cursorActual, new RepString(_propiedadFuente, pTexto));
cursorActual += 10;
}
private void IniciarCursor()
{
cursorActual = rPosTop;
}
#endregion
}
}


Resultado final:



Tamaño del reporte: 7,82KB

Sunday, December 09, 2007

Convertir cadenas a texto capital

Muchas veces queremos formatear una cadena en caracteres con la primera letra de cada palabra en mayúsculas. Esto puede hacerse muy fácilmente con un poco de código, pero no siempre querremos que todas la letras sean convertidas, por ejemplo un artículo (el, la , los, etc) u otra palabra que no deba ser convertida. Por ejemplo, podemos tener el siguiente título:
"Declaración Jurada De Liquidación De Sueldos Para La Planilla Anual De La Empresa"

Puede ser que se vea mejor de la siguiente manera:
"Declaración Jurada de Liquidación de Sueldos para la Planilla Anual de la Empresa".

Para ello explicaré el siguiente código desarrollado en C#:

Primero que nada se tiene la enumeración CaracterNoCapital, la misma que define el conjunto de palabras que no serán convertidas a caracter capital.



public enum CaracterNoCapital
{
a = 1,
al,
con,
de,
del,
el,
ello,
en,
es,
la,
le,
las,
lo,
los,
mi,
no,
por,
para,
que,
te,
se,
si,
su,
un,
una,
y,
}


luego se tiene la clase Capital, la que expone un sólo método público estático, que requiere un texto a ser transformado y devuelve la cadena formateada. El código a continuación ha sido documentado en sus líneas para ser comprendido.


public class Capital
{
public static string ConvierteACapital(string pTexto)
{
// Se obtiene la coleccion de strings formateada
string[] partesCadena = FormatearCadena(pTexto);

//letraCapital = "";
string primeraLetra = "";
bool esCaracterNoCapital = false;

CaracterNoCapital miEnum = new CaracterNoCapital();
// Se obtienen los elementos de la enumeracion EnumCaracteresNoCapital
string[] enumArray = Enum.GetNames(miEnum.GetType());

for (int i = 0; i < escaracternocapital =" false;" a ="="" escaracternocapital =" true;" i ="="" primeraletra =" (partesCadena[i][0].ToString()).ToUpper();" aux =" 0;" letracapital =" new">= partesCadena.Length-2 )
letraCapital.Append(parte);
else
{
letraCapital.Append(parte);
letraCapital.Append(" ");
}
aux++;
}

return letraCapital.ToString();
}

private static string[] FormatearCadena(string pCadena)
{
// Se eliminan los espacios de los extremos de la cadena
pCadena = pCadena.ToLower().Trim();
// Se separa por el caracter ' '
string[] split = pCadena.Split(' ');

string textoParaSeparar = "";

foreach (string parteCadena in split)
{ // Se omiten espacios extra innecesarios
if (parteCadena != ""){
// Se añade cada parte de la cadena que no sea vacio
textoParaSeparar += parteCadena + "^";
}
}
// finalmente se separa el texto por el caracter "^"
string[] partesCadena = textoParaSeparar.Split('^');
return partesCadena;
}
}



Puntos clave
El algoritmo tiene por objetivo general aceptar una cadena, convertir a minúsculas toda la cadena, eliminar espacios en blanco, separar la cadena en palabras, identificar las palabras no capitales(definidos en la enumeración CaracterNoCapital) y finalmente formatear la cadena.

Sunday, July 29, 2007

Reportes en PDF con Report.net

Después de un buen tiempo lejos del mundo blog, vuelvo para hablar de una herramienta que me ha servido para hacer los reportes PDF en ya 3 sistemas de información, me refiero al open-source Report.net, una librería gratuita hosteada en sourceforge (report.net).

Se trata de una librería .net diseñada en lenguaje c# para generar reportes en PDF mediante asp.net y código puro y duro. Aunque a primera vista report.net puede parecer la vuelta al infierno de la generación de reportes, con una adecuada organización de código, llega a ser una herramienta excepcional para la generación de reportes con resultados que igualan y algunas veces superan a los acostumbrados reporteadores "visuales" tales como clásico Crystal Reports o XtraReports de DevExperience.


¿Ventajas?

Pues uno tiene el control total del reporte, es decir, puede manajar todos los aspectos del reporte, no sólo del cargado de datos, sino la creación dinámica de elementos según la programación lo requiera y defina. La libertad otorgada se resume en la customización completa del resultado del reporte. La librería funciona para las versiones 1.1, 2.0 y 3.0 de .net framework.

¿Desventajas?

Al no contar con una interfaz visual, es necesario definir todos y cada uno de los elementos del reporte, desde una tabla, línea de texto o caja de dibujo hasta una constante para definir los bordes. Se debe tener instalado Adobe Acrobat Reader, sugiero que esté instalada a partir de la versión 5.

¿Que tipo de contenido puedo generar?

Pues casi de todo: tablas, cuadros, adición de imágenes, párrafos, listas, formas, etc. Basta con descargar los ejemplos y ver los resultados que pueden realizarse.


Bueno, creo que es hora de un "Hola mundo". Para ello:

  1. Descargar la librería de aqui...

  2. Adicionar la librería Reports.dll a la carpeta bin de nuestra solución web.

  3. Crear una página asp.net llamada PaginaReporte.aspx y en el code-behind pegar el siguiente código

  4. Correr la página y listo.




using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using Root.Reports;
using System.Drawing;

public partial class PaginaReporte : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ReporteEjemplo reporte = new ReporteEjemplo();
RT.ResponsePDF(reporte, this);
}
}

public class ReporteEjemplo:Report
{
FontDef _definicionFuente;
FontProp _propiedadFuente;

protected override void Create()
{
NuevaPagina();
InicializarPropiedadesReporte();
ImprimirHolaMundo();
}

private void InicializarPropiedadesReporte()
{
// Este estilo de fuente debe ser definido sólo una vez
_definicionFuente = new FontDef(this, FontDef.StandardFont.TimesRoman);
_propiedadFuente = new FontProp(_definicionFuente, 10, Color.Navy);
}

private void ImprimirHolaMundo()
{
page_Cur.AddCT_MM(100, 50, new RepString(_propiedadFuente, "Hola mundo... ¿que esperabas?"));
}
internal void NuevaPagina()
{
new Root.Reports.Page(this);
}
}

Espero publicar mas ejemplos de reportes para esta librería los siguientes días para ayudar a aquellos que como yo se han visto en la necesidad de crear reportes de manera gratuita.

Monday, November 13, 2006

Olimpiadas ACM en Bolivia

Pues estoy orgulloso de decir que la Universidad Católica sacó 1º, 5º y 6º lugar en el concurso de programación del ACM(http://acm.uva.es) realizado el pasado 11 de noviembre de 2006 en la Universidad de Aquino. Me da gusto también decir que una de las personas que participaron es mi compañera de la U y del trabajo Ana Rosario Espada (Charito), pues felicidades para ella, los grupos, los cates y a todos nosotros los sistemáticos de la "Cato", que por cierto fuimos notificados poco mas de 2 semanas antes del concurso, pero ya se vió lo que los muchachos pueden dar.

Wednesday, October 18, 2006

Acerca de DaVinci

NOTA: Esta vulnerabilidad ya ha sido informada y corregida en una actualización a este sistema
Existe un programa desarrollado por el servicio de impuestos internos de mi país (Bolivia), el cual es distribuido gratuitamente por la web, ocurre que hoy tratando de ingresar a su interfaz pues no sabía que usuario ingresar, supongo que es la falta de interés por leer los manuales y explicaciones del mismo sitio,

o.0, jeje en fin, como no sabia como entrar pues intenté ingresar "por la fuerza", haciendo un poquito de SQL Injection en el nombre de usuario y password con el siguiente texto:
' or 1=1 --

(este es la clásica sentencia de entrada para hacer una inyección)
pero solo me salía este curioso mensaje: TYPE MISMATCH IN EXPRESSION '(- ' AND PASSWORD = ' OR 1=1--')'. , mmmmm curioso no?

¿por que no intentar con algo mas interesante?

yyyy pues bien a darle con : 'or''=' y listo!

pues ahora el usuario 'or''=' entra tranquilamente al programa.

Pues tampoco pude hacer gran cosa ahi, pero si una recomendación al equipo de programación del DaVinci, que por cierto está bastante bueno.

Mi primer entrada

Hola a todos, esta es mi primer entrada.

La verdad es que no tengo planeado el tipo de contenido que va a ir en esta página, pero supongo que habrá una mezcolanza de tooodo lo que se me ocurra ponerle desde cosas como líneas de libros maravillosos como Llave de Oro o Arpas Eternas de Josefa Rosalía Luque hasta datos de código fuente del desarrollo que llevo a cabo en mis actividades en .net y artículos acerca de esto, jeje supongo que será interesante.

pues bien a empezar.