Cercar en aquest blog

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à