jueves, 25 de diciembre de 2008

Introduccion a conectores de BizTalk R2 para WCF

Hace algún tiempo vengo trabajando con las nuevos adaptadores de WCF que vienen incluidos en la versión R2 de BizTalk 2006, y la idea de este post es solo dar una pequeña introducción a lo que me toca utilizar de todo este conjunto de nuevas herramientas y en algunos post posteriores iré publicando como consumir desde BiztTalk servicios publicados con WCF y las distintas opciones para esto.
Como la mayoría de los que puedan leer este post sabrán, WCF ofrece un rango bastante amplio de posibilidades a cerca de las opciones de cómo consumir un servicio WCF publicado, estas opciones o “bindings” varían tanto en el tipo de transporte y configuraciones de seguridad, pero en general las opciones serian las de la siguiente tabla:









Comenzar con un Send-Port Basico


Comenzaremos creando un Send Port que utiliza el adaptador WSHttpBinding. En este primer paso nuestro objetivo seria integrarse endpoint que se se construye por defecto al crear un servicio WCF en Visual Studio 2008.



Lo primero que deberíamos hacer es asegurarnos que el servicio este levantado y la configuración de su binding se corresponda con el Send Port que estamos creando, esto seria simplemente poner la URL en un IExplorer, verificar que el WSDL del servicio se muestra correctamente y además el binding del servicio expuesto como se muestra en la imagen






Realizados esto pasos tendremos que seleccionar el adaptador y luego podemos hacer click "Configure" para configurar como el adaptador WSHttpBinding como debería ser usado.







Donde los datos que deberemos completar este tipo de Send-Port son realmente muy pocos, por un lado la URL del servicio, por el otro la Soap-Action del methodo que queremos consumir en este Send-Port y cuyo "wsdl:operation name" coincide también con la operación de del servicio que queremos instanciar. (esto es básicamente copiar del WSDL al TextBox: Action como se muestra a continuación).

Muestra del WSDL del servicio:

Configuración del puerto para consumir la operación del WSDL marcado arriba:




Eso seria todo por ahora, en próximos post prometo mostrar como consumir servicios con Custom Binding, que por cierto son bastante mas complejos de consumir y configurar.

Espero que pueda servirles.

Ariel Serlin

martes, 23 de diciembre de 2008

Cargar hoja de Excel (.xls) en GridView de Asp.Net

Algo que a menudo sucede, es que nuestros usuarios pueden tener "bases de datos" enteras en sus computadores en formato Excel y por alguna cuestión que desconozco repentinamente quieren comenzar a utilizarlas dentro de un determinado sistema como una fuente de datos para no tener que cargar todo de nuevo.

Una posible aproximación a solucionar este problema es la que trato de mostrar acá, que básicamente seria importar una hoja de MS Excel a un GridView de Asp.Net, una vez cargada en nuestra grilla, poder darles la posibilidad a nuestros usuarios de corregir algún dato. Finalmente quedaría recorrer la grilla y guardar estos datos en nuestra DB o procesarlos de alguna otra manera (si alguien tiene problema con esta ultima cuestión por favor no dude en escribir). También es válido aclarar que en el ejemplo asumo de antemano que conocemos la estructura del Excel que pretende bindearse al nuestro GridView.


Yendo directamente el punto, la idea en es poder utilizar al motor de consultas JET 4.0, de la misma manera en la que lo utilizaríamos para consultar cualquier otra fuente de datos (una base de datos de MS Acces por ejemplo).

Les copio el código, que me parece que habla por sí solo y más abajo un link con una solución de prueba en la que dejo también incluido un archivo de Excel con el que se podrá probar la solución, solo deberán seleccionar el archivo y luego darle un click al botón importar.

 protected void btnImportarNomina_Click(object sender, EventArgs e)
    {
        if (nominaExcel.PostedFile != null)
        {
            List<Lista> listaCollection = new List<Lista>();
         
             StringBuilder sbConnection = new StringBuilder();
                sbConnection.Append("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=");
                if (nominaExcel.PostedFile.FileName.Contains(".xls"))
                {
                    sbConnection.Append(nominaExcel.PostedFile.FileName);
                    sbConnection.Append(";Extended Properties=Excel 8.0;Persist Security Info=False");
                    System.Data.OleDb.OleDbConnection SQLCon = new System.Data.OleDb.OleDbConnection(sbConnection.ToString());
                    System.Data.OleDb.OleDbCommand SQLCom = new System.Data.OleDb.OleDbCommand("select * from [Hoja1$]", SQLCon);
                    System.Data.OleDb.OleDbDataAdapter SQLDa = new System.Data.OleDb.OleDbDataAdapter(SQLCom);
                 
                    SQLCon.Open();
                    IDataReader Odbreader = SQLCom.ExecuteReader();
                    listaCollection.Clear();
                    while (Odbreader.Read())
                    {
                        Lista lista = new Lista();
                        if (!String.IsNullOrEmpty(Odbreader[0].ToString()))
                        {
                            lista.NumeroDocumento = Convert.ToInt32(Odbreader[0]);
                            lista.Nombre = Odbreader[1].ToString();
                            lista.FechaNac = Convert.ToDateTime(Odbreader[2]);
                            listaCollection.Add(lista);
                        }
                    }
                    SQLCon.Close();
                    GridView1.DataSource = listaCollection;
                    GridView1.DataBind();
                }
        }
    }


Ariel Serlin

Para bajar el codigo hace click aqui

domingo, 21 de diciembre de 2008

Consultar usuarios de Active Directory desde C#

Algo que puede resultar muy útil en algunos casos es tener que consultar información de los usuarios de la red dados de alta en Active Directory desde nuestra aplicacion, en este caso con C#.


Para comenzar deberemos tener en cuenta que es necesario poder contar con un usuario dado de alta en Active Directory, aunque con mínimos permisos. Este usuario con el que deberemos contar sera el usuario que se conecte a nuestro Active Directory(en el caso del código este ejemplo debería agregarse su información en nuestro web.config). Y servirá para el caso en el que querramos obtener por ejemplo el correo electrónico, nombre, apellido, o algún otro dato de cualquier usuario, solo teniendo su loguin por ejemplo.

Yendo puntualmente a la solución de nuestro problema, lo primero que deberemos hacer en nuestro proyecto es referenciar al assembly System.DirectoryServices, posteriormente deberemos hacer un using de la misma





Así de simple podremos consultar la información de nuestros usuario de la siguiente manera

Si bien el código que sigue no tiene grandes complicaciones, básicamente consta de dos clases (en el mismo archivo ), que para el caso de la primero solo modela un usuario con sus propiedades y la segunda contiene un método con el comportamiento necesario para conectarse a nuestro AD, a través del usuario configurado en algún archivo de configuracion.


using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.DirectoryServices;
namespace FindUSers
{
    public class Usuarios
    {
        private int id_User;
        public int Id_User
        {
            get { return id_User; }
            set { id_User = value; }
        }
        private string login;
        public string Login
        {
            get { return login; }
            set { login = value; }
        }
        private string password;
        public string Password
        {
            get { return password; }
            set { password = value; }
        }
        private string email;
        public string Email
        {
            get { return email; }
            set { email = value; }
        }
        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }
        private string names;
        public string Names
        {
            get { return names; }
            set { names = value; }
        }
  
    }
    public class GetUsersInfo
    {
        public List<Usuarios> FindName(Usuarios usuario)
        {
            //This info can become from web.config
         
                string userAD = ConfigurationSettings.AppSettings["UserAD"];
                string passAD = ConfigurationSettings.AppSettings["PassAD"];
                string ldap = "LDAP://" + ConfigurationSettings.AppSettings["LDAP"];
                string strSearchAD = "";
                if (usuario.Email != "")
                {
                    strSearchAD = "(mail=" + usuario.Email.ToLower() + ")";
                }
                if (usuario.LastName != "")
                {
                    strSearchAD += "(sn=" + usuario.LastName + ")";
                }
                if (usuario.Login != "")
                {
                    strSearchAD += "(sAMAccountName=" + usuario.Login + ")";
                }
                List<Usuarios> listUsuarios = new List<Usuarios>();
                //DirectoryEntry adEntry = new DirectoryEntry("LDAP://Domaincontroler", "user", "pass", AuthenticationTypes.Secure);
                DirectoryEntry adEntry = new DirectoryEntry(ldap, userAD, passAD, AuthenticationTypes.Secure);
                System.DirectoryServices.DirectorySearcher adSearch = new System.DirectoryServices.DirectorySearcher(adEntry);
            
                adSearch.Filter = "(&(objectClass=user)" + strSearchAD + ")";
                SearchResultCollection objResultados;
                //adResult = adSearch.FindOne(); // if only i need the first returned user 
                objResultados = adSearch.FindAll();
                foreach (SearchResult MiObjeto in objResultados)
                {
                    Usuarios usarioToAdd = new Usuarios();
                    usarioToAdd.Email = MiObjeto.Properties["mail"][0].ToString();
                    usarioToAdd.Login = MiObjeto.Properties["sAMAccountName"][0].ToString();
                    usarioToAdd.Names = MiObjeto.Properties["givenName"][0].ToString();
                    usarioToAdd.LastName = MiObjeto.Properties["sn"][0].ToString();
                    listUsuarios.Add(usarioToAdd);
                }
                return listUsuarios;
       
        }
    }
}

Adjunto el código correspondiente al proyecto en el que se encuentra el archio .cs con las dos clases del ejemplo (recuerden agregar un archivo .config con las entradas necesarias ), espero que sirva.

Ariel Serlin

Para bajar el codigo hace click aqui

jueves, 4 de diciembre de 2008

Suscribirse a multiples IDOCs en una misma ReceiveLocation ( Biztalk )

Tuve un asunto hace poco en mi trabajo en la que necesitaba suscribirme a mas de un IDOC de SAP y por una cuestión de orden y buenas practicas en la arquitectura del proyecto de EAI en el que estoy trabajando los IDOCs debían ser recepcionados por la misma receive location.
La solucion vino de la mano de un Groso y en este post trato de pasar en claro la forma en la que puede hacer andar esto y por supuesto configurarlo.
La idea es básicamente crear una Pipeline la cual se encargue de desensamblar los IDOCs que lleguen a una determinada receive location y posteriormente configurar la pipeline construida en la receive location que necesitamos realice el trabajo.

El primer paso seria como venimos hablando generar una nueva Pipeline.
Debido a que los esquemas que Biztalk genera cuando importamos la estructura del IDOC sera local en cada proyecto en el que se hizo la importación, pero publico para cualquier proyecto que referenecie voy a hacer de cuenta que los esquemas son importados en los proyectos en los que se encuentran las orquestaciones con lógica y la pipeline se desarrollara en un assembly aparte.

En definitiva los proyectos de Biztalk o assemblys que contendría los esquemas de los IDOCs se verían así en el caso del primero:

Y así para el caso del segundo (pueden ser la cantidad que uno quiera o necesite):








En la siguiente instancia toca construir la Pipeline que nos va a solucionar el problema, la misma podría estar en un assembly aparte, esto es porque sera necesario referenciar las proyectos anteriormente construidos. Resumiendo en tres pasos el proceso de construcción de este proyecto serian básicamente, construirlo, referenciar los assemblys que contienen los esquemas correspondientes a cada IDOC y agregar una Pipeline de recepción que "desensamble" el IDOC correspondiente. Para esto en la Pipeline deberemos agregar tanto shapes de Flat File Disassemble como esquemas de IDCOs tengamos referenciados y configurar en cada sahpe arrastrado un el esquema correspondiente.











En lo que respecta a desarrollo esto seria todo. Quedaría finalmente hacer deploy de nuestros assemblys en el servidor y configurar, que es por cierto la parte mas sencilla, simplemente al crear nuestra Receive Location creada para recibir los IDOCs informarle que debera utilizar la Pipeline creada y recientemente desplegada en nuestro server de la siguiente manera:




Eso seria todo, espero que pueda servirle.

Ariel Serlin

lunes, 1 de diciembre de 2008

Logging "Sencillo" en Biztalk

En la casi todas las ocasiones en las que uno trabaja con Biztalk Server, es imprescindible poder loguear resultados, mensajes o excepciones en algún archivo de texto plano o en el visor de eventos de nuestro server, ya que al no tener interfaz de usuario la única manera de poder analizar detalladamente la ejecución de nuestro flujo de trabajo (workflow) diseñado es analizando el log escrito por la orquestación. Indudablemente lo más conveniente y aconsejable para esta tarea seria utilizar alguna de las librerías ya diseñadas para esta tarea, podrían ser Enterprise Library o Log4Net las más conocidas y que de hecho funcionan bastante bien.

Pero debido a que el uso de estas librerías implica tener que configurar o modificar archivos de conflagración y confeccionar algunos mas en el caso de EntLib, en muchos casos para poder hacer pruebas rápidas o para el caso en el que el entorno va a ser utilizado solo para probar alguna versión nueva de alguna tecnología (me a tocado tener que trabajar en varias maquinas virtuales ) dejo esta pequeña assembly en la cual existen 2 métodos.
El primero solo loguea el valor de alguna variable y el segundo permite escribir contenido de todo un mensaje en un archivo de log.
El código de la clase conteniendo ambos métodos seria:

[Serializable]







     public class ArielLog







    {















        public static void WriteValue(string value)







        {







            File.AppendAllText("C:\\ArchivosLog.txt", value);







            System.Diagnostics.EventLog.WriteEntry("BizTalkLog", value);







        }








        public static void WriteMessage(XLANGMessage msg)







        {







            XmlDocument doc = (XmlDocument)msg[0].RetrieveAs(typeof(XmlDocument));











            string mensaje = doc.InnerXml;







            File.AppendAllText("C:\\Mensjaes.txt", mensaje);







        }








    }




Y para usar estos dos métodos simplemente restaría referenciar a la assembly en la que se encuentra la clase que los contiene y ya podrían ser llamados desde cualquier shape de expresión de la siguiente manera:

Para loguear un mensaje









O para loguear el valor de una variable:


Eso seria todo, por si alguien quiere recompilar la librería para cambiarle el nombre o lo que fuera, adjunto una solución con el código de la assembly firmado para poder ser subida a la GAC y así poder utilizarla desde Biztalk Server.

Ariel Serlin


Para bajar el código hace click aquí