Cercar en aquest blog

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à

15/7/10

Disseny: Una aproximació a la capa de negoci

Un cop fet l’ anàlisi funcional de qualsevol aplicació cal fer el disseny d’aquesta de manera que s’inclogui o encaixi dins l’arquitectura del conjunt d’aplicacions que formen l’entramat de sistemes d’ informació de l’empresa.

Per tant, previament hem de disposar d’una arquitectura que ens permeti encaixar qualsevol aplicació nova que volem desenvolupar.

Al meu parer, aquesta arquitectura ha de donar la posibilitat de que la seva implementació ha de ser independent de la seva distribució, i per tant de com s’accedeix a ella per part de l’usuari en podem parlar més endavant. Per mi una aplicació dins el món dels serveis no és res més que un contracte de funcionalitats (interface) i la implementació d’aquestes.

Quan implementem, podem veure que definim entitats noves i pot ser que en reutilitzem algunes altres.

“Les entitats són classes persistents, on dues del mateix tipus es diferencien per un identificador únic”

D’aquestes obtenim dos requisits indispensables dins el nostre sistema. Una és la operativa,, amb aquestes entitats hem de fer alguna cosa, i l’altre és l’enmagatzament de la seva informació, persitència de les entitats. Pel que fa la part operativa, definirem un contracte amb totes les operacions que podem dur a terme amb una entitat i els seus agregats (entitats dèbils). I pel que fa a la persitència, cal buscar una arquitectura que ens permeti fer operacions de persitència independenment de lloc (BD, Fitxer, servei, etc) on s’acabi enmagatzeman. El patró de disseny triat és el “Repository Pattern”.

Un cop resumit més o menys una part del disseny, la part que englobaria tota la capa de negoci, especifiquem-ho una mica més.

Per mi la capa de negoci d’un sistema empresarial ha de ser distribuible, de diferents maneres, flexible i productiva (fàcilment escalable). Tampoc ha de ser cap problema l’augment de nivells (servidors) on aquesta es troba allotjada.

CAPA DE NEGOCI



Bé amb la imatge anterior podem veure com veig jo la capa de negoci d’un sistema empresarial.

Capa Aplicació: Aqui es defineixen el contractes de les diferents aplicacions i s’implementen, Per exemple si tenim una aplicació que gestiona l’administració de pacients, una altre que gestiona l’assistència de les hospitalitzacions i una altre la de les urgències, en aquesta capa definiriem els contractes de les operacions o funcions extretes dels anàlisis funcionals duts a terme pels analístes. També implementariem aquests contractes. La implementació de les funcionas es basarà en orquestrar serveis de la capa de domini.

Capa de domini: La més important. El patró escollit és el “DDD-Domain Driven Design”. Crec que és una bona opció. En aquesta capa, seguint el patró decrit, es defineixen les entitats, es defineixen i s’implementen els contractes d’operaions de cada entitat i els seus agregats, i es defineixen les operacions del repositoris de cada entitat, però no s’implementen.

Capa de Infrastructura: Aqui és on implementem els repositoris de cada entitat. Aquest són els que acaben fent operacions de persistència a la BD, fitxer , Servei.

Evidenment això no és tot, cal practicar a fons la POO en la implementació, abstracció, herència, especilització, generalitació, etc. D’aquesta pràctica en sortiran els “cores” de cada capa.









Freemarket.com Marketplace