6.11.2010

Invocar un Workflow desde Otro Workflow y Detectar el Evento de Terminación de cada Workflow

Una tarea muy común cuando se usa el Workflow Foundation es invocar un workflow desde otro Workflow. Esta tarea no tiene mucha dificultad; sin embargo, en muchas ocasiones me he encontrado con la necesidad de atrapar el evento de finalización de uno de los dos workflow para llevar a cabo una acción determinada. Este post detalla lo que se debe hacer para saber cuando finalizó el workflow que estamos buscando.

En primera instancia vamos a crear un proyecto de Consola que contenga un workflow integrado secuencua – lo vamos a usar a manera de ejemplo, porque para un escenario en la vida real, deberíamos escojer una librería de workflow. Vamos a crear un workflow secuencial sencillo con un “Code Activity” al inicio del workflow y otro al final del workflow. En el medio de ambas actividades vamos a colocar la actividad de invocación del otro workflow. La siguiente figura nos muestra el workflow secuencial comentado.

image

El código de las actividades de código ( valga la redundancia :) ) se presenta a continuación:

private void InicializarWorkflow(object sender, EventArgs e)
{
Trace.WriteLine("Iniciando el Workflow 1");
}

private void WorkflowFinalizado(object sender, EventArgs e)
{
Trace.WriteLine("Workflow 1 Finalizado");
}



Lo único que harán esas actividades es poner un mensaje en la pantalla de output de Visual Studio cuando estemos ejecutando la aplicación, lo cual lo hago con el fin de que se pueda ver el orden de ejecución del workflow – es importante destacar que el trace es una clase que esta en el namespace System.Diagnostics, por lo tanto tenemos que incluir el namespace utilizando la directiva usign.



Seguidamente procedemos a crear un segundo workflow secuencial, el cual tendrá solamente un “Code Activity” el cual nos indicará que estamos ejecutando el workflow 2.



image



El código de la actividad funciona igual que las anteriores



private void IniciandoWF2(object sender, EventArgs e)
{
Trace.WriteLine("Iniciando Workflow 2");
}



Ahora procedemos a configurar la figura del workflow 1 en donde se invoca el workflow 2. Esto lo hacemos seleccionado la Actividad “invokeWorkflowActivity1” y en la propiedad TargetWorkflow le damos click al botón para que nos aparezca la pantalla para seleccionar el workflow que queremos llamar.



image









Una vez seleccionado el workflow, las propiedades de la actividad para invocar el workflow 2 deberían quedar así:



image



y el workflow 1 debería verse así:



image



El siguiente paso es determinar cuando ha finalizado el workflow 1 y cuando ha finalizado el workflow 2. Para lograrlo, primero vamos a ir al método main de la consola, y vamos a cambiar el handler para el método WorkflowCompleted perteneciente al Runtime y vamos a agregarle el método para que se vea de la siguiente forma:



using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += workflowRuntime_WorkflowCompleted;
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(InvocarOtroWF.Workflow1));
instance.Start();

waitHandle.WaitOne();
}



Seguidamente procedemos a codificar el handler del evento WorkflowCompleted:



static void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
if (e.WorkflowDefinition is Workflow1)
{
Trace.WriteLine("Workflow 1 Completado");
}
else
{
Trace.WriteLine("Workfow 2 Completado");
}
}



Como se puede ver en el código anterior, el evento workflow completed en la variable e del tipo WorkflowCompletedEventArgs tiene una propiedad llamada WorkflowDefinition, la cual me da el tipo del workflow que disparo el evento. En este caso para verificar cual workflow disparó el evento, simplemente debo de preguntar si esta propiedad es del tipo Workflow1; si es así, procedo a indicarlo con la clase Trace de lo contrario el workflow que lanzó el evento es el Workflow 2.



Si ejecutamos esta aplicación, veremos los resultados en el output Window de Visual Studio tal y como se ve en la siguiente figura:



image



Hay que notar la diferencia entre el texto de Workflow finalizado escrito por la actividad de código y el evento workflow completado del runtima, ya que este último es un evento disparado por el runtime de los workflows cuando recibe una notificación indicandole que el workflow X esta completo y no hay más actividades por ejecutar, mientras que en la actividad, es simplemente el código que pusimos en la actividad y que debe de ejecutarse cuando el flujo del workflow vaya por la misma, lo cual es diferente a que este completado.




Technorati Tags: ,,

6.10.2010

Error Configurando el Enterprise SSO con Biztalk Server 2009

Resulta que tenía una instalación de Biztalk Server 2009 en mi máquina con Vista Enterprise y Visual Studio 2008 la cual funcionaba perfectamente – en especial para demos o pruebas antes de llevar la orquestación a producción. Por una razón de negocio, tuve que desinstalar el Biztalk SErver 2009 de mi máquina por un tiempo, y por lo tanto desinstalar el SSO. Hoy trato de instalar Biztalk en mi máquina de nuevo y me encuentro con el siguiente error de configuración

“Failed to connect to SQL Database SSODB”

Resulta que aunque reinstalé el SSODB – que es necesario para la configuración de Biztalk, no me permitía seguir con la configuración del servidor y me pedía que configurara correctamente el SSODB.

Después de luchar un poco – desinstalar un par de veces – y buscar en la web, me encontré que lo que sucedía era que tenía que registrar de nuevo el componente de SSO llamado SSOSQL.DLL – el cual estaba registrado con la configuración anterior – y listo. Tal y como se ve en la siguiente figura, para registrarlo se utiliza el comando regasm ssosql.dll.

image

Una vez registrado, el Enterprise SSO se configura correctamente y la configuración de Biztalk Server continúa normalmente.

image

Technorati Tags: ,

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: