Cercar en aquest blog

31/10/10

Distribució del negoci (PART IV)

Bé, en aquest post exposaré com crear un client d' un servei WCF. Fer-ho amb la opció del VS és bastant fàcil. El que faré és exposar com fer una classe genèrica que sigui capaç de generar un client transparent per qualsevol servei, coneixent només les operacions d'aquest (interficie) i els missatges que exposa per interactuar amb ell (contractes de dades).

Primer de tot creerem una llibreria que anomenarem TransparentProxy. I dins d'ella una interfície on definirem les operacions que ha de complir el proxy i una classe que ens implementarà un proxy.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TransparentProxy
{
    interface IProxy<T>
        T Client {get;}
        void Close();
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TransparentProxy
{
    public class Proxy<T>: IProxy<T>
    {
        public T Client
        {
            get { throw new NotImplementedException(); }
        }
        public void Close()
        {
            throw new NotImplementedException();
        }
    }
}

Un cop fet això començarem a implementar el proxy. Per fer-ho em de tenir uns mínims coneixements de WCF.
Bàsicament per conectar-nos a un servei necessitem saber:
  1. La adreça on es troba.
  2. Com és vincualen el client i el servei (binding).
  3. El tipus de seguretat en el transport i el missatge.
  4. I si cal, usuari i clau d'accés. SEMPRE HEM D'UTILTZAR UN MECANISME DE AUTENTIFICACIÓ I AUTORITZACIÓ.
I saber que tot això ho trobem al "assembly" System.ServiceModel .

Realment gran part de tot l'esmentat depén del tipus de vincul que volem implementar, i per tant en una primera versió, es una dada que se li ha de comunicar al proxy.

Així doncs us presento una mínima expressió d'un proxy transparent, molt bàsic, però útil per començar a especialitzar-lo cap els nostres serveis. Jo, per exemple, utilitzo serveis federats amb ADFS 2.0, i m'he creat un proxy transparent capaç de conectar-se a qualsevol dels meus serveis.







using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace TransparentProxy
{
    public class Proxy<T>: IProxy<T>
    {
        ChannelFactory<T> ch;
       
       public Proxy(Binding bind, string addr , string userName, string password )
        {

            ch = new ChannelFactory<T>(bind, new EndpointAddress(addr));
            if ((userName != null) && (password!=null))
            {
                // És un exemple, les credencials poden ser passades
                // d'altres maneres, certificats, tokens, etc.
                // Cal docuementar-se.
                
                ch.Credentials.UserName.UserName = userName;
                ch.Credentials.UserName.Password = password;
            }
        }
        
        public T Client
        {
            get { return ch.CreateChannel(); }
        }


        public void Close()
        {
            ch.Close();
        }
    }
}
 


Exemple d'utilització

WSHttpBinding bind=new WSHttpBinding();
bind.Security.Mode = SecurityMode.Message;
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
bind.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
bind.Security.Message.NegotiateServiceCredential = true;
TransparentProxy.IProxy proxy = new TransparentProxy.Proxy(bind, "http://localhost:53538/WCFGAPService/Service.svc", null, null);
IList res = proxy.Client.LListarMetges();
proxy.Close();
return res;


En el proper post conectarem un client Winforms amb el servei, utilitzant el proxy transparent.


28/10/10

Una Petita intromissió: Gràfic per triar el 'Binding' en un servei WCF

Mirant per internet he trobat aquesta imatge d'allò més interesant.

22/9/10

Distribució del negoci (PART III)

Finalment només ens queda distribuir realment el negoci. Fins ara només tenim llibreries. Necessitem d’alguna tecnologia que ens ajudi a fer arribar als clients les funcionalitats que hem implemetat. Podem pensar-ne moltes però serem practics, la intenció sempre és faclitari no complicar. Podem distribuir-lo amb una aplicació ASP.Net, amb un Web Service o amb un WCF Services. La primera no es la que jo vull, ja que els meus clients seran aplicaions Winforms. La segona està moltbé però hi ha capes que no comtempla, com són diferents tipus de trasnport i seguretat. I per tant distribuirem amb un servei WCF, de manera mot fàcil, Si coneixem la tecnologia, ens podem adonar que donar diferents opcions de comunicació es molt fàcil de fer i treballar amb diferents maneres d’autentificació i autorització també. Així com garantir la seguretat tant a nivell de transport com de missatge. Però tot això són carecterístiques pòpies de WCF independents del negoci que distribueixen. Aqui está la gràcia de arquitecturar els sistemes en capes i nivells.
Primer de tot crerem un nou projecte Web WCF. Un cop fet, agreguerem les referencies a les llibreries que implementen el negoci que volem distribuir. Esborrem totes les classes que tenim a la carpeta App_Code. Editem el “Service.svc” (podem canviar-li el nom si volem), i el modifiquem de la següent manera:





Un cop fet això obriem el Web.config i el modifiquem afegint el nostre negoci com a un servei.




I el provem. Funciona!!!. Ara només li falta afegir configuracions de comportament i seguretat. Però abans de tot jo tinc el costum de provar que funciona i després ja el perfeccionarem. El següent pas serà doncs, crear un client i provar.

10/9/10

Distribució del negoci (PART II)

Un cop tenim definit el servei, pasem a la implementació. Per això afegirem una nova llibreria a la solució que anomenarem ServeisDistribuits.Ingresos.ModulPrincipal.dll.

Afagirem una clase que anomenarem Servei.cs i farem que implementi la interficie IModulPrincipal de la llibreria anteriorment creada. En la implementació de les operacions es on hem de delegar les funcions a la capa de Aplicació on hi ha el negoci o orquestrar (secuenciar) operaciosd’aquesta per poder crear la resposta de la operació del servei en questió. Si ho fem així, aconseguim separar totalment la definició de la implementació. Això pot no tenir sentit en petites aplicacions, però quan la cosa és molt gran podem tenir versions diferents implementades de la mateixa definició. Això facilitat molt la escabilitat, flexibilitat, la reutilització i el desacoplament de capes, i treball en equip, facilitant la posibilitatde fer test abans tenir versions finals, només cal una mica de imaginació.



També hem de pensar que aquesta és l libreria que implementa el servei, i per tant haurà d ser capaç de transmetre els missatges d´error (excepcions) i controlar l’ accés dels usuaris “loginats” en la estació client (en un altre post explicaré com fer-ho demanera molt fàcil)



El codi seria més o menys el seguents.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace ServeisDistribuits.Ingresos.ModulPrincipal
{
    public class Servei:IModulPrincipal
    {
        public IList CercarPacient(CriteriCercarPacient criteri)
        {
            // Aqui podem fer una traça personalitzada d'entrada (usuari, PC, Hora, Missatge entrada....)
            
            // Declarem la variable de retorn

            IList llista = new List();
            try
            {
                // Invoquem el negoci (GAP.dll) i 
                // omplim la llista i la retornem Ex: GAP.Search("Pacients",...

                return llista;
            }
            catch (Exception e)
            {
                // Capturem l'error
                // Fem una traça detallada Ex: Tracert(e)
                // i finalment llacem un missatge al client
                throw new FaultException(".... error .....");
            }
        }

        public IList LListarMetges()
        {
             // Aqui podem fer una traça personalitzada d'entrada (usuari, PC, Hora, Missatge entrada....)
            
            // Declarem la variable de retorn

            IList llista = new List();
            try
            {
                // Invoquem el negoci (GAP.dll) i 
                // omplim la llista i la retornem Ex: GAP.Search("Metges",...

                return llista;
            }
            catch (Exception e)
            {
                // Capturem l'error
                // Fem una traça detallada Ex: Tracert(e)
                // i finalment llacem un missatge al client
                throw new FaultException(".... error .....");
            }
        
        }

        public IList LlistarLlits(LlitEstats estat)
        {
            // Aqui podem fer una traça personalitzada d'entrada (usuari, PC, Hora, Missatge entrada....)

            // Declarem la variable de retorn

            IList llista = new List();
            try
            {
                // Invoquem el negoci (GAP.dll) i 
                // omplim la llista i la retornem Ex: GAP.Search("Llits",...

                return llista;
            }
            catch (Exception e)
            {
                // Capturem l'error
                // Fem una traça detallada Ex: Tracert(e)
                // i finalment llacem un missatge al client
                throw new FaultException(".... error .....");
            }
        }

        public ResultatOperacio Ingresar(DadesIngres dades)
        {
            // Aqui podem fer una traça personalitzada d'entrada (usuari, PC, Hora, Missatge entrada....)

            // Declarem la variable de retorn

            ResultatOperacio  resultat = null;
            try
            {
                // Invoquem el negoci (GAP.dll) i 
                // Executem el negoci Ex: GAP.Save(dades
                // i retornem el resultat.

                return resultat;
            }
            catch (Exception e)
            {
                // Capturem l'error
                // Fem una traça detallada Ex: Tracert(e)
                // i finalment llacem un missatge al client
                throw new FaultException(".... error .....");
            }
        }
    }
}

4/9/10

Distribució del negoci (PART I)

Imaginem que tenim desenvolupat tot el negoci de la Gestió Administrativa de Pacients (GAP) en el nostre nou sistema assistencial. Aquesta part del sistema gestiona diferents arees, com poden ser, dades administratives de pacients (adreces, documents identifiatus, relacions parentals, expedients, etc), ingressos, altes, llistes d’espera i citacions. Evidenment, aquestes parts seran gestionades/utilitzades per usuaris/professionals diferents, amb rols diferents, o sigui, amb permisos per fer algunes coses i altres no.
Seguim imaginant, o no, que volem desenvolupar una aplicació que gestioni només la part d’ingresos (el més obvi seria que gestionés ingressos i altes, però serem simplistes). I per tant i seguin amb la meva proposta de disseny, creerem un servei distribuit que encapsuli les operacions (funcions) necessàries per dur a terme aquesta feina.

Seguim sent simplistes, i ens imaginem que tot el negoci el tenil encapsulat en una llibreria que anomenarem GAP.dll. Les funcions que distribuirem sortiran directament d’aqui o orquestrades a partir de funcions d’aqui. Si fem un anàlisi molt simple del que suposa ingressar una persona trobem que hi participen dos actors i un element d’ ubicació:

  1. El metge A ingressa al pacient P1.
  2. On?
  3. Al llit H15B, que no està ocupat.


Per fer això l’usuari haurà de poder realitzar aquesta relació. Per tal de poder fer-ho haurà de poder seleccionar el pacient, el metge i un llit lliure. Un cop fet això fer l’ingrés.
Seguim sent simples. El nostre hospital és molt petit, només té 20 llits i 4 metges. De pacients en tenim més 25. “Per fer una petita demo ja n’hi ha prou.


Un cop fet el petit anàlisi pasem a la implementació (només hem de distribuir una part del negoci implementat).


Primer de tot, creerem una llibreria que anomenarem:
ServeisDistribuits.Ingresos.dll amb el Visual Studio ( jo utilitzo el 2010).
Dins la llibreria creerem una interfície amb totes les operacions. Aquesta interfície defineix el contracte del servei i l’anomenarem IModulPrincipal.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace ServeisDistribuits.Ingresos
{
    [ServiceContract]
    public interface IModulPrincipal
    {
        /// 
        /// Trona una llista de pacients a partir d'un criteri de recerca
        /// 
        /// 
Criteri de recerca/// 
        [OperationContract]
        IList CercarPacient(CriteriCercarPacient criteri);
        /// 
        /// Retorna la llista de pacients actius
        /// 
        /// 
        [OperationContract]
        IList LListarMetges();

        /// 
        /// Retorna un llista de llits que cumpleixen un estat
        /// 
        /// 
/// 
        [OperationContract]
        IList LlistarLlits(LlitEstats estat);
        /// 
        /// Operació (Verb) que fa l'ingrés
        /// 
        /// 
Dades de l'ingrés/// 
        [OperationContract]
        ResultatOperacio Ingresar(DadesIngres dades);


    }
}

Com podem veure les operacions com a màxim tenen un parametre d' entrada (un missatge d'entrada i un missatge de sortida)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
    /// 
    /// Missatge que representa el criteri de recerca de Pacients
    /// 
    [DataContract]
    public class CriteriCercarPacient
    {
        /// 
        /// Part inicial del Cognom1
        /// 
        /// 
        [DataMember]
        public String Cognom1Comenca;
        /// 
        /// Part Inicial del cognom2
        /// 
        /// 
        [DataMember]
        public String Cognom2Comenca;
        /// 
        /// Part inicial del Nom
        /// 
        /// 
        [DataMember]
        public String NomComenca;

    }
}

--------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
    public class DadesIngres
    {
        [DataMember]
        public String IdPacient;
        [DataMember]
        public String IdMetge;
        [DataMember]
        public String IdLlit;
        [DataMember]
        public String Observacions;
    }
}
---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
    [DataContract]
    public class InformacioLlits
    {
        [DataMember]
        public String Id;
        [DataMember]
        public EstatLlit Estat;

    }

    public enum EstatLlit
    {
        Buit=1,Ocupat=2
    }
}

---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
    [DataContract]
    public class InformacioMetges
    {
        [DataMember]
        public String Id;
        [DataMember]
        public String NomMetge;

   
    }
}
---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
    [DataContract]
    public class InformacioPacient
    {
        [DataMember]
        public String Id;
        [DataMember]
        public String NomPacient;
    }
}
---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ServeisDistribuits.Ingresos
{
    public enum LlitEstats
    {
        Tots=0, Buits=1, Ocupats=2
    }
}
---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ServeisDistribuits.Ingresos
{
   [DataContract]
    public class ResultatOperacio
    {
       [DataMember] public String Missatge;
    }
}


.... continuarà
Freemarket.com Marketplace