4.03.2010

Invocando un Servicio Web desde JavaScript en ASP.NET

En una de las tareas que normalmente uno tiene que llevar a cabo, me encontré con la necesidad de invocar un servicio Web –asmx – desde javascript en mi página cliente. Los detalles del porque tenía que llevar a cabo esta tarea de esta forma son irrelevantes para el propósito del post, sin embargo me parece que la solución del problema puede serle útil a muchos de ustedes.

En primera instancia, vamos a crear un servicio web muy simple y le vamos a llamar WebServiceObtenerValor.asmx. Este servicio web simplemente recibe un string, lo concatena con el string de respuesta y se retorna la respuesta. Por supuesto, aquí pudimos haber ido a traer datos a una base de datos, a leer un archivo de configuración, cargar una imagen, etc. El código del servicio se ve a continuación.

using System.Web.Services;

[WebService(Namespace = "http://www.formsevolution.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebServiceObtenerValor : WebService {
[WebMethod]
public string ObtenerValor( string parametro) {
return "Obteniendo el Valor solicitado:" + parametro;
}
}


Un punto importante a destacar es el uso del atributo [System.Web.Script.Services.ScriptService] el cual nos permite que este servicio sea invocado desde el script manager de Ajax.NET de manera asincrona.



El siguiente paso es configurar el script manager del lado del cliente en la página aspx. Para esto, vamos a agregar una referencia al servicio desde el ScriptManager utilizando el ServiceReference presente dentro del ScriptManager.



<asp:ScriptManagerID="ScriptManager1"runat="server">

    <
Services>        <asp:ServiceReferencePath="~/WebServiceObtenerValor.asmx" />

    </
Services>

</
asp:ScriptManager>




El último paso es crear los métodos en java script para procesar el llamado, inicialmente vamos a agregar dos controles de tipo HTML – un textbox y un botón – y los vamos a utilizar para hacer el llamado. El evento click del botón va a tener el llamado al web service, y vamos a utilizar el DOM para obtener el valor del texto que acabamos de escribir.



image



En la invocación del servicio, al ser este asincrónico, debemos indicar donde se espera la respuesta del servicio en caso de que sea exitosa, donde esperar un timeout o donde esperar un error. En todos los casos vamos a desplegar una alerta con la respuesta recibida, sin embargo, podríamos hacer con los datos retornados lo que como desarrolladores necesitemos en la página.



    <script language="javascript" type="text/javascript">
// <!CDATA[

function Button1_onclick() {
ret = WebServiceObtenerValor.ObtenerValor(document.getElementById('Text1').value, OnComplete, OnTimeOut, OnError);
return (true);
}

function OnComplete(arg) {
alert(arg);
}

function OnTimeOut(arg) {
alert('Timeout invocando el servicio');
}

function OnError(arg) {
alert('Error en la invocación del servicio');
}
// ]]>
</script>



Technorati Tags: ,,

3.21.2010

Donde va el Workflow Foundation en una Arquitectura n-Layer

Desde que salio la primera versión del Workflow Foundation con el Framework 3.0, se ha ido incrementando su uso en las organizaciones para llevar a cabo diversas tareas que por lo general, son procesos que no se ejecutan de inmediato, si no más bien son procesos que perduran en el tiempo. Igualmente, el WF se esta conviertiendo en el framework de preferencia cuando se trata de procesos que necesitan enviar notificaciones, o hacer seguimiento estricto de los procesos que se van ejecutando - tracking.

Esto es una muy buena noticia ya que nos permite desarrollar de forma más simple nuestras aplicaciones utilizando el Workflow Foundation, lo que además nos permite tener una forma más sencilla y mantenible de orquestar nuestros procesos de negocio. El uso del workflow foundation nos trae otra pregunta, ¿dónde en mi arquitectura n-layer pongo mis workflows? Esta es la pregunta que vamos a contestar en este blog post.

Es muy común asociar los framework para crear workflows con pantallas y demás componentes que nos facilitan el desarrollo de aplicaciones – en realidad no lo facilitan, solo lo aceleran y solamente en el caso de que sea estándar, cuando aparecen cosas que requieren de programación, por lo general es más dificil crear el cambio personalizado que hacerlo manualmente. Sin embargo, al utilizar estos workflows que me generan automáticamente los procesos y las pantallas, quedo automáticamente atado a la interface gráfica seleccionada, por lo tanto si deseo permitir el acceso de otros esquemas de interacción a mis workflows voy a tener que hacer el workflow de nuevo, específicamente para el tipo de front end al que deseo crearle el workflow. Esto por supuesto no es lo que se persigue con las arquitecturas n-layer. Por esta razón es que lo ideal es tener workflows que permitan ser activados desde distinitas fuentes, ya sea UI o capas de servicios. Para lograr esto, debemos empaquetar los workflows en librerías lo que nos permitiría invocar estos workflows ya sea desde servicios, aplicaciones web, aplicaciones móviles, y aplicaciones RIA, etc.

Por otro lado, como mencionamos anteriormente, la función del workflow es orquestar procesos de negocio. Como claramente lo dice la oración anterior el workflow nos debe ayudar a orquestar el negocio por lo tanto se denota claramente que debemos orquestar procesos de negocio basándonos en nuestra lógica de negocio, no basados en un tipo de interacción que vayamos a tener con alguna interfase gráfica o con una capa de servicios. Esto esta reflejado así por el grupo de pattern and practices desde el año 2002 mucho tiempo antes de que saliera el Workflow Foundation como se puede ver en la siguiente figura obtenida de la guía Application Architecture for .NET: Designing Applications and Services.

Ee658109.4bee4a28-6791-4df2-8c8c-9a45d9afcf6a(en-us,PandP.10).png

Como podemos ver en esta figura, en la parte de lógica de negocios están estipulados los workflows de negocio, pero ¿por qué así? Bueno, porque la idea del workflow es orquestar procesos invocando métodos del negocio, no creando el código del negocio dentro del workflow todo esto con el fin de facilitar la mantenibilidad del proceso. Además, que pasaría si queremos llamar un método sin usar el workflow que lo contiene, pues si el código esta en el workflow, tendríamos que reprogramarlo, pero si esta dentro de un componente de lógica de negocios el mismo código se utiliza en el llamado desde el workflow como del servicio o el UI que lo este invocando.

Wrokflow as a Service

Si revisamos los componentes disponibles en la versión del workflow que esta en el framework 3.0 y la que esta en el 3.5 vemos que solo varía en dos figuras.

image

El SendActivity es para consumir un servicio – ojo que no dice un servicio Web aunque esta incluido a la hora de escribir servicio - y el ReceiveActivity. Este último nos permite exponer un workflow como un servicio, lo cual nos permite a cumplir en parte la arquitectura que estamos viendo en la figura tomada del pattern and practices.

3.07.2010

Hacer una consulta con LinqToEntites que se comporte como un like en SQLServer

En estos días recibí una pregunta de parte de un alumno muy interesante: ¿Cómo hacer una consulta en LinqToEntites que se comporte como un like %parametro% en SQLServer. En este post voy a responder esta pregunta. En primera instancia vamos a usar una tabla que llamaremos participantes la cual vemos a continuación.

image

Seguidamente en la lógica de negocios vamos a hacer una consulta donde se nos devuelvan los registros en donde el nombre sea igual al que enviamos por parámetros o el nombre contenga el parámetro en alguna parte. La consulta es la siguiente:

public List<Participantes> ObtenerParticipantesPorNombre(Participantes participante)
{
var participantes = from p in entities.Participantes
where p.Nombre.IndexOf(participante.Nombre) > -1
select p;
return participantes.ToList();
}



Como se puede ver en la consulta, lo que hacemos en la condición where de la sentencia de LinqToEntities es aprovecharnos de los métodos de la clase string. En este caso utilizamos el método IndexOf el cual nos devuelve el índice de la primera ocurrencia positiva en la comparación de dos strings. Esto quiere decir que si el nombre que viene en la clase participante (una entidad del Entity Framework) hace match con alguna parte del nombre – ejemplo iego en Diego – nos va a retornar un valor superior a –1. Si lo que queremos es garantizarnos que el nombre debe iniciar con un string especifico, entonces utilizamos el método StartsWith como se muestra a continuación:



public List<Participantes> ObtenerParticipantesPorNombre(Participantes participante)
{
var participantes = from p in entities.Participantes
where p.Nombre.StartsWith(participante.Nombre)
select p;
return participantes.ToList();
}



La diferencia radica en que el método StartsWith devuelve verdadero si el string que estamos evaluando inicia con el string que estamos pasando por parámetro. Con estos dos métodos podemos tener un comportamiento similar al Like %parametro% de SQL.



Technorati Tags: ,

2.27.2010

Usando el ObjectDataSource en una Aplicación n-Layer

Uno de los controles menos utilizando cuando se desarrollan aplicaciones en .NET es el objeto ObjectDataSource. He visto en muchas ocasiones el uso del objeto SqlDataSource para conectarse directamente a una base de datos SQL y realizar operaciones contra la misma, pero en raras ocasiones he visto a los desarrolladores aprovecharse del objecto ObjectDataSource y sacarle verdaderamente provecho. Para entender como funciona este objeto, vamos a crear una aplicación Web que nos va a permitir obtener registros a través de este control y despelgarlos en un DataGrid.

El ObjectDataSource es un objeto que se pega directamente a los métodos contenidos en una clase específica. Idealmente a los métodos de nuestra lógica de negocios. Por esta razón vamos a construir una tabla llamada temarios y vamos a crear una capa de acceso a datos utilizando el Entity Framework.

En la siguiente imagen se muestra la tabla temarios la cual es con la que vamos a trabajar.

image

Seguidamente vamos a crear nuestra capa de acceso a datos y agregar un modelo del Entity Framework para tener acceso vía ORM al repositorio de datos.

image

image

El siguiente paso es crear nuestra logica de negocios. Para esto vamos a crear otra librería en la cual vamos a agregar las clases y la lógica de negocio necesario desde nuestra página de temarios. En esta capa vamos a usar LinqToEntities. Nótese el nombre de los métodos resaltado, porque los vamos a utilizar desde el ObjectDataSource.

image

Seguidamente creamos una página Web y le agregamos un DataGrid el cual llamaremos dgTemarios.

image

Ahora procedemos a agregar un objectDataSource dentro de nuestra pantalla y le damos click en el tag de ayuda donde dice “Configure Data Source”.

image

En la primera pantalla del wizard, seleccionamos el componente y la clase del cual queremos utilizar los métodos para acceder al repositorio de datos, en nuestro caso vamos a utilizar la clase Temario_BL de la lógica de negocios de la aplicación.

image

En la siguiente pantalla del wizard procedemos a configurar el ObjectDatasource. Como podemos ver en la figura siguiente, el wizard nos presenta las cuatro operaciones básicas y nos permite seleccionar los métodos que queremos para cada una de las operaciones. En nuestro caso, vamos a seleccionar ObtenerTemarios, el cual retorna una lista genéricas de la entidad Temario - List<Temario>.

image

El objectDataSource debe verse así una vez configurado con el método select – Nótese que no estamos obligados a configurar todos los métodos del objectDataSource.

image

El último paso es ligar el Datagrid con el ObjectDataSource. Para lograr esto, procedemos a modificar la propiedad DataSourceId a través del tag inteligente del grid y seleccionado el datasource deseado en el combo de Choose Data Source tal y como lo muestra la siguiente figura.

image

Con esto, ya podemos obtener los registros desde el repositorio de datos.

1.23.2010

Creando Gráficos tipo Pastel con el WPF toolkit

En un post anterior, hicimos una simple gráfica utilizando el WPF toolkit en donde mostrabamos como crear una grafica lineal en donde se mostraban las pulgas reportadas versos las pulgas corregidas. En este post vamos a crear la misma gráfica pero utilizando un gráfico tipo pie.

A diferencia del post anterior, esta vez vamos a agregar las series de forma dinámica de forma que podamos agregar series de diferentes tipos, por esta razón, la declaración del chart en XML lucirá de la siguiente manera:

image

Igualmente, vamos a agregar dos Radio button, uno para presentar el chart de forma lineal y otro para presentarlo como un pie.

image

El siguiente paso es crear un método para generar el gráfico lineal. Esta vez tenemos que crear las series, configurar las propiedades, agregar la colección de datos a desplegar, y agregar la serie al chart tal y como se ve en el siguiente código.

private void CrearGraficoLineal()
{
chartBugs.Series.Clear();
LineSeries BugsReported = new LineSeries();
BugsReported.Title = "Bugs Reported";
BugsReported.DependentValuePath = "Cantidad";
BugsReported.IndependentValuePath = "Fecha";
BugsReported.AnimationSequence = AnimationSequence.FirstToLast;
BugsReported.ItemsSource = LoadBugReported();

LineSeries BugsFixed = new LineSeries();
BugsFixed.Title = "Bugs Fixed";
BugsFixed.DependentValuePath = "Cantidad";
BugsFixed.IndependentValuePath = "Fecha";
BugsFixed.ItemsSource = LoadBugFixed();
BugsFixed.AnimationSequence = AnimationSequence.FirstToLast;

chartBugs.Series.Add(BugsReported);
chartBugs.Series.Add(BugsFixed);
}


Seguidamente procedemos a crear el método para crear las series tipo Pie. El código es exactamente al anterior, solamente que la instancia de la serie que se crea no es LineSeries sino PieSeries.



private void CrearGraficoLineal()
{
chartBugs.Series.Clear();
LineSeries BugsReported = new LineSeries();
BugsReported.Title = "Bugs Reported";
BugsReported.DependentValuePath = "Cantidad";
BugsReported.IndependentValuePath = "Fecha";
BugsReported.AnimationSequence = AnimationSequence.FirstToLast;
BugsReported.ItemsSource = LoadBugReported();

LineSeries BugsFixed = new LineSeries();
BugsFixed.Title = "Bugs Fixed";
BugsFixed.DependentValuePath = "Cantidad";
BugsFixed.IndependentValuePath = "Fecha";
BugsFixed.ItemsSource = LoadBugFixed();
BugsFixed.AnimationSequence = AnimationSequence.FirstToLast;

chartBugs.Series.Add(BugsReported);
chartBugs.Series.Add(BugsFixed);
}



Ahora solo falta invocar los métodos desde los eventos del radio button.



private void rdbLineal_Checked(object sender, RoutedEventArgs e)
{
CrearGraficoLineal();
}

private void rdbPastel_Checked(object sender, RoutedEventArgs e)
{
CrearGraficoPastel();
}





Al ejecutar el ejemplo anterior, los gráficos generados son los siguientes:



image



image





Oportunidad de Mejora



Como podemos ver en el código anterior, estamos repitiendo exactamente el mismo código para generar las series, con la excepción de que se crean instancias diferentes dependiendo del tipo de la serie que deseamos. Para optimizar este código, podríamos unificar estos métodos en uno solo y que genere una instancia de la serie deseada en base a un parámetro en el método que genera los gráficos. Si vemos en el object browser(F12), nos damos cuenta que ambas series heredan de la clase DataPointSeries, la cual es una clase abstracta.



image



Por esta razón, y aprovechandonos del polimorfismo podemos crear una serie del tipo DataPointSeries e instanciar la clase con el tipo que se nos indique vía parámetro. Para llevar a cabo esta tarea, iniciamos creando una enumeración para identificar los tipos de gráficos de forma consistente.



public enum TipoGrafico
{
Pastel,
Lineal
} ;


Seguidamente creamos el método unificado utilizando como tipo del parámetro la enumeración TipoGrafico, además creamos las instancias de las series en una estructura if dependiendo del valor en el parámetro.



private void CrearGrafico(TipoGrafico grafico)
{
chartBugs.Series.Clear();
DataPointSeries bugsReported = null;
DataPointSeries bugsFixed = null;

if (grafico == TipoGrafico.Lineal)
{
bugsFixed = new LineSeries();
bugsReported = new LineSeries();
}
else if (grafico == TipoGrafico.Pastel)
{
bugsFixed = new PieSeries();
bugsReported = new PieSeries();
}

if (bugsReported != null)
{
bugsReported.Title = "Bugs Reported";
bugsReported.DependentValuePath = "Cantidad";
bugsReported.IndependentValuePath = "Fecha";
bugsReported.AnimationSequence = AnimationSequence.FirstToLast;
bugsReported.ItemsSource = LoadBugReported();
chartBugs.Series.Add(bugsReported);
}
if (bugsFixed != null)
{
bugsFixed.Title = "Bugs Fixed";
bugsFixed.DependentValuePath = "Cantidad";
bugsFixed.IndependentValuePath = "Fecha";
bugsFixed.ItemsSource = LoadBugFixed();
bugsFixed.AnimationSequence = AnimationSequence.FirstToLast;
chartBugs.Series.Add(bugsFixed);
}
}



Nótese que si alguna de las series declaradas es nula, no se agrega al chart. Por último, cambiamos la invocación de los radio button hacia los métodos para generar las series.



private void rdbLineal_Checked(object sender, RoutedEventArgs e)
{
CrearGrafico(TipoGrafico.Lineal);
}

private void rdbPastel_Checked(object sender, RoutedEventArgs e)
{
CrearGrafico(TipoGrafico.Pastel);
}



Al ejecutar la aplicación, el resultado es el mismo que se obtenía con los métodos separados.



Technorati Tags: ,,,

1.08.2010

Linq y los Árboles de Expresiones ( Expression Trees) – Parte 1

Los árboles de expresiones nos permiten parsear expresiones enviadas a un método. Un árbol de expresiones en Linq es como lo indica su nombre, una estructura de árbol que contiene expresiones. Las expresiones por otra parte, en este caso particular son expresiones Lambda, las cuales como vimos en un post pasado, son una nueva manera de definir un delegate en C#. El árbol de expresiones es una estructura de datos que contiene expresiones lambda compiladas.

Los árboles de expresiones son dinámicos, ya que al igual que los delegates, permiten cambiar en tiempo de ejecución la expresión a ejecutar; es decir, estos árboles son estructuras que contienen expresiones que se utilizan para procesar los datos. Para entender como funcionan los árboles de expresiones vamos a analizar un ejemplo. En primera instancia, vamos a tener una clase Producto.

public class Producto
{
public int Id { get; set; }
public string Nombre { get; set; }
public double Precio { get; set; }

public Producto(int id, string nombre, double precio)
{
Id = id;
Nombre = nombre;
Precio = precio;
}
}



Seguidamente vamos a crear un arreglo de productos y vamos a aplicarle una expresión lambda utilizando un árbol de expresiones.



private static void ApplyFunction()
{
Producto[] productos = {
new Producto(1, "Laptop", 500),
new Producto(2, "Monitor", 300),
new Producto(3, "Zune HD", 230),
new Producto(4, "IPod Touch", 200),
new Producto(5, "Black Berry Storm", 540),
new Producto(6, "Wii", 199)
};

String Message = "";
Expression<Func<Producto, Boolean>> expProductos = miProducto => miProducto.Precio > 299;
foreach (Producto producto in productos)
if (expProductos.Compile().Invoke(producto))
Message = Message + producto.Nombre + "\r\n";
Console.WriteLine(Message);
}


La parte del árbol de expresiones empieza en la parte de la creación de lo que parece un bloque de código complejo. La clase Expression<T> acepta un delegate prototipo como parámetro. El delegate se define usando el delegate genérico Func<T, TResult>. En este caso, el delegate genérico acepta un string como parámetro de entrada y retorna un booleano.Sin embargo, se pueden utilizar cualquier tipo en la entrada o en el retorno que se requiera en la aplicación. La definición de la expresión viene de seguido, expProductos contiene una expresión booleana que recibe un string y devuelve un booleano, el cual es determinado a partir del precio del producto – si es mayor de 99 retorna true, de lo contrario retorna false. En este punto, expProductos contiene una estructura árbol que incluye todos los elementos requeridos para la expresión lambda: miProducto => miProducto.Precio > 299;



Para invocar la función se invoca la expresión utilizando Compile().Invoke(producto) donde se evalúa la variable que se envía por parámetro y se retorna verdadero si cumple con la expresión, o falso si no lo cumple.



En el siguiente post vamos a crear un árbol de expresiones desde 0.



Technorati Tags: ,,

1.06.2010

Entendiendo las Expresiones Lambda

Una de las características menos comprendidas de .NET son las expresiones Lambda. En este post voy a explicar lo más sencillo posible que son, y como funcionan.

Las expresiones lambda son un paso más para soportar programación funcional – aunque no son exclusivas de este paradigma – y a partir de C# 3.0 son consideradas el siguiente paso desde los delegates anónimos. Para comprender mejor como se llego a tener este concepto en C# 3.0 vamos a hacer un viaje en retrospectiva para ver como evolucionó este tema.

Inicialmente teniamos los delegates, los cuales en resumen me permitían pasar referencias a la función para poder ser invocadas por otra funcióna, en lenguaje C++ es un puntero a una función para poder ser utilizada como parámetro.

Por ejemplo, supongamos que queremos tener una función que imprima todos los número impares de un rango que el usuario le proporciona. Se podría crear una función que me indica que un número es impar o no de la siguiente forma:

public static bool EsImpar(int numero)
{
return (numero & 1) == 1;
}


Como queremos aplicarle la función a un grupo de números para determinar si son impares, podríamos crear un delegate – un puntero a una función – y acceder la función anterior como un parámetro. Inicialmente creamos un delegate con la signatura de la función esImpar, es decir con un parámetro int.



public delegate bool ProbarNumero(int numero);


Seguidamente procedemos a crear un método que nos imprima los números impares:



public static void ImprimirLosImpares(int inicio, int final, ProbarNumero prueba)
{
for (int i = inicio; i <= final; i++)
{
if (prueba(i))
Console.WriteLine(i);
}
}


Como podemos ver en este método, estamos pasando el delegate como parámetro para mandar a ejecutar una función la cual tiene como signatura un parámetro de tipo int. Este delegate va a apuntar a la función que yo le envíe por parámetro y la va a ejecutar en la sección del if. Seguidamente invocamos la función ImprimirLosImpares de la siguiente manera:



static void Main(string[] args)
{
ImprimirLosImpares(1, 15, EsImpar);
}



En esta ocasión, le pasamos como parámetro la función es impar, pero pudimos haber enviado como parámetro cualquier función que reciba un entero como parámetro. El resultado al ejecutar este código sería:



image



Esto me da independencia a la hora de invocar los métodos, por que yo podría tener una función imprimir, y varios métodos tales como EsPar, EsImpar, EsPrimo, etc. y utilizarlos cuando lo considere necesario.



En C# 2.0 este concepto de los delegates se extendió con el uso de los métodos anónimos. Los métodos anónimos me permiten eliminar la necesidad de tener que declarar el método y escribirlo en línea. Todo lo que escribimos antes en C#, podemos resumirlo en este método anónimo:



static void Main(string[] args)
{
ImprimirLosImpares(1, 15,
delegate(int numero)
{
return (numero & 1) == 1;
}
);
//ImprimirLosImpares(1, 15, EsImpar);
}


En este caso, en lugar de pasarle el puntero al método, le pasamos un método anónimo directamente como parámetro para que se ejecute dentro de ImprimirLosPares. El resultado al ejecutar este bloque de código es el mismo que el resultado anterior.



Las expresiones lambda son una sintaxis más compacta de lo anterior. Nosotros podemos en C# 3.0+ escribir la funcionalidad anterior simplemente con el siguiente código:



static void Main(string[] args)
{
ImprimirLosImpares(1, 15, numero => (numero & 1) == 1);
}



Las expresiones lamba son siempre de la forma:



parametros => expresión



por lo que en la función anterior, pasamos la variable número como parámetro y luego le aplicamos la condición para definir si es impar o no.



Technorati Tags: ,

12.30.2009

Felices Fiesta !!!

Ahora que termina el año, quiero agredecer a todos los que se han tomado la molestia de leer mi blog, de hacer comentarios, sugerencias y críticas. Espero que lo escrito aquí les haya servido en sus actividades. Espero seguir el otro año escribiendo acerca de los temas más variados que se me ocurran, o como ocurrió este año, que ustedes sugieran. Si tienes interés en algún tema en específico, no dudes en escribirme a diego.rojas [at] gmail.com

Les dejó una postal del MSDN y que pasen un excelente año nuevo!!!

Technorati Tags:

Graficando en WPF Utilizando el WPF Toolkit

En muchos casos cuando se están desarrollando proyectos sobre todo a jefaturas o gerencias, se pide visualización de datos a través de gráficos ya sea en reportes o en pantalla. Normalmente para estos casos ya uno como desarrollador/consultor tiene una suite de controles para graficar que conoce y recomienda, sin embargo; no siempre la empresa que contrata o para la cual uno trabaja tiene presupuesto para invertir en controles – sin embargo para charts web les recomiendo la suite de componentArt – y entonces empieza la búsqueda de controles para graficar gratuitos o más accesibles. Esto por lo general es un verdadero dolor de cabeza porque aunque existen, no todos tienen todo lo que se necesita y por lo general el que pide estos gráficos tiene un gusto y necesidad muy refinado respecto a los datos que desea visualizar. 

Revisando el WPFToolkit de Junio del 2009, me encontré que este contiene – aunque en preview – la facilidad de realizar gráficas en WPF. En este post voy a explicar de forma breve como realizar un gráfico simple utilizando el toolkit y la librería para graficar.

Librerías a Incluir

Cuando se instala el WPF Toolkit, se agrega una cejilla en el toolbox de Visual Studio el cual contiene los controles existentes en el toolkit para graficar.

image

No solo podemos hacerlo de esta forma, si no que también podemos agregar una referencia al dll que contiene los controles de graficación System.Windows.Controls.DataVisualization.Toolkit.dll agregando el namespace en WPF para acceder a estos controles.

image

xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"



En primera instancia vamos a agregar un control de tipo Chart desde el toolbox, el cual es el contenedor de las series que vamos a graficar. El siguiente paso es agregar las series que deseamos ver en el gráfico, vamos a tener una serie por cada colección de datos que queremos graficar.



<chartingToolkit:Chart Margin="0,0,0,0" Name="chartBugs" Background="Silver" BorderBrush="Black" BorderThickness="3" Title="Bugs por Mes" LegendTitle="Bugs del mes" >
<
chartingToolkit:LineSeries Name="BugsReported" Title="Bugs Reported" DependentValuePath="Cantidad" IndependentValuePath="Fecha" AnimationSequence="FirstToLast">
</
chartingToolkit:LineSeries
>
<
chartingToolkit:LineSeries Name="BugsFixed" Title="Bugs Fixed" DependentValuePath="Cantidad" IndependentValuePath="Fecha" AnimationSequence="FirstToLast">
</
chartingToolkit:LineSeries
>
</
chartingToolkit:Chart>



En nuestro caso vamos a graficar las pulgas encontradas en la aplicación en un periodo determinado de tiempo, y las pulgas resueltas. Como podemos ver en el código anterior, la propiedad Title me permite identificar cada una de las series en la gráfica. Existen otras dos propiedades muy importantes que son las que me van a permitir hacer databining con el DataSource que vamos a asignar a cada una de las series, el DependentValuePath es el eje Y y el IndepdentValuePath es el eje X. En modo de diseño nuestra pantalla debe lucir así:



image



Ahora solo nos falta agregarle datos a las series para graficarlas. Estas series se pueden “ligar” al gráfico vía XAML o vía código .NET. En este ejemplo, vamos a utilizar C# para llevar a cabo esta tarea. El código que vamos a utilizar va a obtener la lista de pulgas – resueltas y agregadas – desde una lista genérica del tipo de una clase hecha específicamente para almacenar estas pulgas, esta contiene con dos propiedades una para la fecha y otra para la cantidad de pulgas agregadas. El código de esta clase es el siguiente:



public class BugsReported
{
public DateTime Fecha { get; set; }
public int Cantidad { get; set; }


public BugsReported(DateTime fecha, int cantidad)
{
Fecha = fecha;
Cantidad = cantidad;
}
}



Seguidamente procedemos a llenar las listas con datos aleatorios. Nótese que para agregar la fecha a cada llamado al constructor, utilizo DateTime.Now.AddDays(-X ), lo cual restará días al día actual. Los métodos que llenan ambas listas son los siguientes – se podría hacer uno solo, pero como el objetivo es el graficar entonces así más clarito:



private List<BugsReported> LoadBugReported()
{
BugsReported.Title = "Bugs Reported";
List<BugsReported> reportedBugs = new List<BugsReported>();
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-20), 3));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-19), 8));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-18), 7));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-15), 22));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-12), 9));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-8), 1));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-7), 12));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-6), 2));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-1), 8));

return reportedBugs;

}

private List<BugsReported> LoadBugFixed()
{

List<BugsReported> reportedBugs = new List<BugsReported>();
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-20), 1));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-19), 9));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-18), 4));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-15), 23));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-12), 8));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-8), 0));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-7), 1));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-6), 10));
reportedBugs.Add(new BugsReported(DateTime.Now.AddDays(-1), 7));

return reportedBugs;
}



Por último procedemos a ligar las listas con las series del gráfico. Para hacer esto, creamos una variable del tipo LineSeries – que se encuentra en el namespace 




System.Windows.Controls.DataVisualization.Charting;




- y le asignamos la serie que queremos llenar con datos del chart. Como podemos ver en el código el chart tiene una colección de series y su índice corresponde al orden en que las agregamos al chart. Por último, agregamos el datasource a la propiedad ItemsSource de la serie y listo, estamos graficando.



private void Window_Loaded(object sender, RoutedEventArgs e)
{
LineSeries lineSerieBugsReported = chartBugs.Series[0] as LineSeries;
if (lineSerieBugsReported != null)
{
lineSerieBugsReported.ItemsSource = LoadBugReported();
}

LineSeries lineSeriedBugsFixed = chartBugs.Series[1] as LineSeries;
if (lineSeriedBugsFixed != null)
{
lineSeriedBugsFixed.ItemsSource = LoadBugFixed();
}
}





El resultado al ejecutar el código anterior se puede ver en la siguiente figura:



image




Technorati Tags: ,

12.13.2009

¿Que Código pongo en mi Capa de UI ?

Esta es una pregunta constante que recibo vía blog, o cuando estoy trabajando en el diseño de alguna arquitectura en algún cliente. Normalmente, los desarrolladores comprenden bien de que se trata este asunto de las arquitecturas n-layer, comprenden que poner en la capa de acceso a datos, y tienen una idea general de lo que debe llevar la lógica de negocios. Pero cuando se habla de la capa de presentación hay serias dudas.  Estas dudas se dan principalmente porque estamos acostumbrados a escribir código en las pantallas de nuestras aplicaciones sin cuestionarnos si ese código debería ir en las pantallas – web, mobile, desktop – o no.

Para poder contestar esta pregunta, primero tenemos que entender que código debemos poner en las demás capas. De manera resumida, podemos decir que en la capa de acceso a datos vamos a escribir todo el código necesario para poder acceder nuestro repositorio de datos. Escribimos en esta capa las funciones para consultar, borrar, actualizar o ingresar datos, el código para conectarse a la base de datos y todo los relacionado con la interacción con los repositorios a los que accede nuestra aplicación. En la capa de lógica de negocios escribimos el código relacionado con el proceso que vamos a automatizar. Los objetos de negocio que tengan atributos ( cuando no dividimos el estado del objeto del el comportamiento ) tienen reglas de negocio en sus propiedades e incluso validaciones de asignación o retorno del dato en la propiedad. Nunca se debe acceder el estado del objeto directamente accediendo al atributo, siempre se deben utilizar métodos o propiedades. El siguiente diagrama nos muestra la composición de una instancia de un objeto de negocio y como se debe cambiar el estado del objeto.

image

Si se tiene capa de servicios, en esta capa no debe de tener código de lógica de negocios solamente invocación a componentes de negocio, esto principalmente porque si hay algún cambio a nivel del negocio, todas las interfaces que consumen esa lógica de negocios van a ver reflejado el cambio, sin importar si la consumen via servicio o directamente al componente.

Después de repasar que código poner en cada capa, nos queda solamente indicar que código realmente debemos tener en el UI:

  • Excepciones: Se deben de atrapar los errores que se presenten a nivel de interfaz gráfica y presentar al usuario un error que sea comprensible y que no asuste al usuario
  • Validaciónes: En la capa de UI deben de existir validaciones respecto a la interacción del usuario con la aplicación.
  • Databinding: Se agrega el código necesario para permitir el databinding entre los datos que despliegan controles del UI y que retornan las capas subyacentes.
  • Invocación a la capa de servicios o a la lógica de negocios: Deben de agregarse el código necesario para poder invocar la lógica de negocios de los componentes que estamos utilizando, ya sea a través de la capa de servicios o a través de la lógica de negocios directamente.

Y ahora se preguntarán: ¿En qué me beneficia esto? Pues esto nos va a permitir tener una separación real de capas, con lo que podemos cambiar de tipo de UI sin necesidad de modificar la aplicación, ya que la misma lógica de negocios se va a consumir sin importar el tipo de aplicación que queremos implementar. Si vemos con detenimiento el tipo de código que tenemos que poner en el UI, nos vamos a dar cuenta que por lo general es en estas secciones en donde existen variaciones entre los diversos tipos de UI, por ejemplo, el manejo de eventos para validar e invocar funcionalidad entre una aplicación desktop, una aplicación web, una aplicación mobile y una aplicación RIA.

Technorati Tags: ,