Lógica de Negócio com WCF Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 1 WCF Introdução O que é? Uma tecnologia para suportar o desenvolvimento de aplicações distribuídas orientadas aos serviços, não apenas web services Uma única tecnologia para substituir várias tecnologias diferentes: Enterprise Services, MSMQ, DCOM/.Net Remoting Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 2
WCF Introdução Serviços e endpoints Serviços e clientes comunicam enviando mensagens para endpoints Pode ser qualquer processo hospedeiro cliente endpoint mensagens serviço serviço serviço endpoint endpoint endpoint endpoint endpoint endpoint endpoint endpoint endpoint Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 3 WCF Introdução ABC da comunicação Os clientes necessitam de saber a seguinte informação para comunicarem com um endpoint: Address é a indicação da localização na rede para onde devem ser enviadas as menssagens destinadas ao endpoint (exemplos: http://localhost/servico, net.tcp://servidor/servico) Binding define características dos canais a serem usados para comunicar com o endpoint. Um binding é um conjunto de elementos de binding para especificar os protocolos de transporte (HTTP, TCP, MSMQ, Named pipes,...) e restrições de segurança e transacções. Existem pré-definidos vários bindings (basichttpbinding, wshttpbinding,...) Contract Define as capacidades (funcionalidade) do endpoint. Estes três elementos são independentes entre si Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 4
WCF Introdução ABC da comunicação Os serviços podem opcionalmente incluir um endpoint designado MetaDataExchange (MEX) que os clientes podem usar para obter os ABCs dos endpoints do serviço. O visual studio 2008 usa esta opção quando se escolhe Add Service Reference num projecto e a ferramenta svcutil.exe também a usa. Em ambos os casos, a informação retornada é usada para criar um ficheiro de configuração da aplicação (app.config) e uma classe com a definição de um proxy que permite ao cliente aceder ao endpoint e um ficheiro de configuração da aplicação (app.config) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 5 WCF Introdução Um primeiro serviço O contrato: [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); Podem ter propriedades diferentes Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 6
WCF Introdução Um primeiro serviço O serviço: public class ServicoContas : IServicoContas public float obtersaldo(int numero)... public void alterarsaldo(int numero, float s)... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 7 WCF Introdução Um primeiro serviço O hospedeiro (self hosting): public class Servico public static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(ServicoContas), new Uri("http://localhost:8000/Exemplo1")); host.addserviceendpoint(typeof(iservicocontas), new BasicHttpBinding(),""); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Pode indicar-se o endereço do endpoint. Se não for indicado um URI comleto, concatens-e o endereço do serviço com o que for dado. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 8
WCF Introdução Um primeiro serviço O hospedeiro (self hosting) usando código e app.config: public class Servico public static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(ServicoContas)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 9 WCF Introdução Um primeiro serviço O hospedeiro usando código e app.config: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="exemplo1.servicocontas"> <host> <baseaddresses> <add baseaddress="http://localhost:8000/exemplo1"/> </baseaddresses> </host> <endpoint address="" binding = "basichttpbinding" contract="exemplo1.iservicocontas"/> </service> </services> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 10
WCF Introdução Um primeiro serviço Serviço com MEX configurado por código public class Servico public static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(ServicoContas)); ServiceMetadataBehavior b = new ServiceMetadataBehavior(); b.httpgetenabled = true; host.description.behaviors.add(b); host.addserviceendpoint( typeof(imetadataexchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); host.open();... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 11 WCF Introdução Um primeiro serviço Serviço com MEX configurado em app.config <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="exemplo1.servicocontas" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="http://localhost:8000/exemplo1"/> </baseaddresses> </host> <endpoint address="" binding ="basichttpbinding" contract="exemplo1.iservicocontas"/> <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <servicebehaviors> <behavior name="sb"> <servicemetadata httpgetenabled="true"/> </behavior> </servicebehaviors> </behaviors> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 12
WCF Introdução Um cliente só com código [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); class Cliente static void Main(string[] args) ChannelFactory<IServicoContas> servico = new ChannelFactory<IServicoContas>( new BasicHttpBinding(), new EndpointAddress( "http://localhost:8000/exemplo1")); IServicoContas endpt = servico.createchannel(); float s = endpt.obtersaldo(1); Console.WriteLine("Saldo conta 1 = 0", s);... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 13 WCF Introdução Um cliente configurado com app.config [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); class Cliente static void Main(string[] args) ChannelFactory<IServicoContas> servico = new ChannelFactory<IServicoContas>( "clienteservicocontas"); IServicoContas endpt = servico.createchannel(); float s = endpt.obtersaldo(1); Console.WriteLine("Saldo conta 1 = 0", s);... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 14
WCF Introdução Um cliente configurado com app.config <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <client> <endpoint name="clienteservicocontas address ="http://localhost:8000/exemplo1 binding="basichttpbinding" contract="iservicocontas"/> </client> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 15 WCF Introdução Um cliente usando a opção Add Service Reference do Visual Studio 2008 using ExemploClienteASR.ServiceReference1; namespace Exemplo1ClienteASR class Program static void Main(string[] args) ServicoContasClient proxy = new ServicoContasClient(); float s = proxy.obtersaldo(1); Console.WriteLine("Saldo conta 1 = 0", s); s *= 2; proxy.alterarsaldo(1, s); proxy.close(); O VS usou o MEX do serviço para criar o namespace <nome projecto>.servicereference1 no qual é implementada a classe proxy de nome <nome do contrato>client (*). Também é gerado o ficheiro app.config (ou web.config) com o nó <system.servicemodel> apropriado. (*) Na verdade, <nome do contrato> pode não coincidir com o nome do contrato. Pode ter sido retirado o I inicial (por exemplo em IServicoContas) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 16
WCF Hospedagem Qualquer processo managed pode servir como hospedeiro. Já vimos como hospedar um serviço numa aplicação.net (self hosting) Para além deste tipo de hospedagem, são ainda possíveis: 1. Hospedagem em IIS 2. Hospedagem num serviço windows 3. Hospedagem em Windows Activation Server (WAS) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 17 WCF Hospedagem Hospedagem em IIS Para basichttpbinding, wshttpbindig e wsdualhttpbinding, é possível hospedar os serviços no IIS. Procedimento: 1. Criar uma aplicação virtual no IIS para alojar o serviço 2. Criar um ficheiro com a extensão.svc para definir a implementação do serviço. 3. Acrescentar uma secção <system.servicemodel> a web.config Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 18
WCF Hospedagem Hospedagem em IIS Em ServicoContas.cs: namespace Exemplo1IISManual... [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 19 WCF Hospedagem Hospedagem em IIS Em ServicoContas.cs: public class ServicoContas: IServicoContas public float obtersaldo(int numero)... public void alterarsaldo(int numero, float s)... O assembly Exemplo1IISManual.dll, criado após compilação, deve ser colocado no GAC ou ne pasta /bin da aplicação virtual Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 20
WCF Hospedagem Hospedagem em IIS Em ServicoContas.svc: <%@ServiceHost Language="C#" Service="Exemplo1IISManual.ServicoContas" %> Em web.config: <?xml version="1.0"?> <configuration> <system.servicemodel> <services> <service name="exemplo1iismanual.servicocontas behaviorconfiguration="servicocontasbehavior"> <endpoint address="" binding="basichttpbinding" contract="exemplo1iismanual.iservicocontas"> </endpoint> <endpoint address="mex" binding="mexhttpbinding" contract="imetadataexchange"/> </service> </services> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 21 WCF Hospedagem Hospedagem em IIS Em web.config: <behaviors> <servicebehaviors> <behavior name="servicocontasbehavior"> <servicemetadata httpgetenabled="true"/> <servicedebug includeexceptiondetailinfaults="false"/> </behavior> </servicebehaviors> </behaviors> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 22
WCF Hospedagem Hospedagem em IIS Em alternativa poderiamos ter em ServicoContas.svc: 1. <%@ServiceHost Language="C#" Service="Exemplo1IISManual.ServicoContas CodeBehind="~/App_Code/ServicoContas.cs" %> Neste caso na primeira utilização o fichiero ServicoContas.cs seria compilado 2. <%@ServiceHost Language="C#" Service="Exemplo1IISManual.ServicoContas" %> Código do serviço Nesta caso o código seria compilado por cada invocação do serviço Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 23 WCF Hospedagem Hospedagem wm WAS Para Windows Vista e Windows Server 2008, é possível hospedagem em Windows Process Activation Services (WAS), o qual suporta multiplos protocolos ao nível de transporte (HTTP, net.tcp, net.pipe, net.msmq,...). O WAS também suporta process activation, recycling e identity management. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 24
WCF Hospedagem Hospedagem em Managed Windows Service Os MWS são controlados pelo Service Control Manager (SCM) e administrados através de Microsoft Management Console (MMC), ou de outras ferramentas que utilizem a as APIs Windows Management Instrumentation (WMI) e SCM. O VS2008 tem uma opção de projecto para MWS Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 25 WCF Hospedagem Hospedagem em Managed Windows Service namespace Exemplo1MWS [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); public class ServicoContas : IServicoContas public float obtersaldo(int numero) public void alterarsaldo(int numero, float s) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 26
WCF Hospedagem Hospedagem em Managed Windows Service [RunInstaller(true)] // auto-instalação // O nome pode ser diferente, pois o atributo é que conta public class ProjectInstaller : Installer // installutil.exe. private ServiceProcessInstaller pi; private ServiceInstaller si; public ProjectInstaller() pi = new ServiceProcessInstaller(); pi.account = ServiceAccount.LocalSystem; si = new ServiceInstaller(); si.servicename = "Exemplo1MWS"; si.description = "Teste de WCF"; Installers.Add(pi); // informação sobre o processo a instalar Installers.Add(si); // descrição do serviço a instalar Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 27 WCF Hospedagem Hospedagem em Managed Windows Service public partial class ServicoMWS : ServiceBase public ServicoMWS() InitializeComponent(); protected override void OnStart(string[] args) ServiceHost host = new ServiceHost(typeof(ServicoContas)); host.open(); ServiceEndpoint ep = host.description.endpoints[0]; EventLog.WriteEntry(ep.Contract.Name+ " iniciado. Endpoint: "+ ep.address+ " Binding "+ ep.binding.name, System.Diagnostics.EventLogEntryType.Information); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 28
WCF Hospedagem Hospedagem em Managed Windows Service protected override void OnStop() EventLog.WriteEntry("Exemplo1MWS terminado", System.Diagnostics.EventLogEntryType.Information); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 29 WCF Hospedagem Hospedagem em Managed Windows Service static class Program static void Main() ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] new ServicoMWS() ; ServiceBase.Run(ServicesToRun); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 30
WCF Hospedagem Endereços de serviços e endpoints. Dado que um serviço é uma colecção de endpoints, o endereço do serviço pode servir de base para esquemas de endereçamento relativo dos endpoints (mas não é obrigatório). Exemplo:... <host> <baseaddresses> <add baseaddress="http://localhost:8000/exemplo1"/> </baseaddresses> </host> <endpoint address="" binding = "basichttpbinding" contract="exemplo1.iservicocontas"/> <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> Endereço: http://localhost:8000/exemplo1 Endereço: http://localhost:8000/exemplo1/mex Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 31 WCF Hospedagem Endereços de serviços e endpoints. Podem existir vários endereços do serviço, mas apenas um por cada esquema de URI. Os conflitos nos endpoints que usem os mesmos endereços relativos são resolvidos pelos bindings. Exemplo:... <host> <baseaddresses> <add baseaddress="http://localhost:8000/exemplo1"/> <add baseaddress= net.tcp://localhost:8001/exemplo1"/> </baseaddresses> </host> <endpoint address= ep" binding = "basichttpbinding" contract="exemplo1.iservicocontas"/> <endpoint address = ep" binding = nettcpbinding" contract = "Exemplo1.IServicoContas"/> Endereço: http://localhost:8000/exemplo1/ep Endereço: net.tcp://localhost:8001/exemplo1/ep Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 32
WCF Hospedagem Hospedagem de multiplos serviços no mesmo processo: Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 33 WCF Contratos Web Services Description Language (WSDL) é um formato XML para descrever serviços (de rede) como um con junto de ports (endpoints) que operam sobre mensagens as quais contêm informação orientada para os procedimentos ou informação orientada para os documentos. As operações e mensagens são definidas de forma abstracta e associadas (bind) a um protocolo concreto de rede e a um fromato concreto de mensagem de forma a definirem um endpoint. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 34
WCF Contratos Elemento Type Message Operation PortType Binding Port Service Descrição Definições de tipos de dados usados para descrever a troca de mensagens (em regra XSD) Definição abstracta dos dados a transmitir. Uma mensagem consiste em várias componentes lógicas com definição num sistema de tipos (Type) O nome e descrição de uma acção suportada pelo serviço que expõe a parte da capacidade e funcionalidade de um endpoint Um conjunto (com nome) de operações relacionadas e mensagens abstractas envolvidas. Um endpoint implementa um PortType (service contract) Define o formato das mensagens e detalhes dos protocolos de comunicação definidos para um PortType particular Especifica um endpoint particular indicando um endereço particular para um Binding Define um conjunto de Ports relacionados Os contratos são uma forma simples de associar elementos CLR a descrições WSDL Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 35 WCF Contratos [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); public class ServicoContas : IServicoContas public float obtersaldo(int numero) public void alterarsaldo(int numero, float s)... <service name="exemplo1iismanual.servicocontas behaviorconfiguration="servicocontasbehavior"> <endpoint address="" binding="basichttpbinding" contract="exemplo1iismanual.iservicocontas"> </endpoint> <endpoint address="mex" binding="mexhttpbinding" contract="imetadataexchange"/> </service>... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 36
WCF Contratos <?xml version="1.0" encoding="utf-8"?> <wsdl:definitions name="servicocontas" targetnamespace="http://tempuri.org/" xmlns:wsdl=... > <wsdl:types> <xsd:schema targetnamespace="http://tempuri.org/imports"> <xsd:import schemalocation=... />... </xsd:schema> </wsdl:types> <wsdl:message name="iservicocontas_obtersaldo_inputmessage"> <wsdl:part name="parameters" element="tns:obtersaldo" /> </wsdl:message> <wsdl:message name="iservicocontas_obtersaldo_outputmessage"> <wsdl:part name="parameters" element="tns:obtersaldoresponse" /> </wsdl:message>... <wsdl:porttype name="iservicocontas"> <wsdl:operation name="obtersaldo"> <wsdl:input wsaw:action="http://tempuri.org/iservicocontas/obtersaldo message="tns:iservicocontas_obtersaldo_inputmessage" /> <wsdl:output wsaw:action="http://tempuri.org/iservicocontas/obtersaldoresponse message="tns:iservicocontas_obtersaldo_outputmessage" /> </wsdl:operation>... </wsdl:porttype> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 37 WCF Contratos <wsdl:binding name="basichttpbinding_iservicocontas" type="tns:iservicocontas"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="obtersaldo"> <soap:operation soapaction="http://tempuri.org/iservicocontas/obtersaldo" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="servicocontas"> <wsdl:port name="basichttpbinding_iservicocontas" binding="tns:basichttpbinding_iservicocontas"> <soap:address location= "http://sisad_mobile.ssic.deetc.win.isel.ipl.pt/exemplo1iismanual/servicocontas.svc" /> </wsdl:port> </wsdl:service> </wsdl:definitions> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 38
WCF Contratos Service contracts: [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); void naoobjectodocontrato(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 39 WCF Contratos Service contracts: Propriedades de ServiceContract: Name controla a propriedade name no elemento <porttype> do WSDL (por omissão, o nome da interface do contrato) Namespace idem, mas para a propriedade namespace (por omissão http://tempuri.org) SessionMode indica se o contrato exige um binding que suporte sessões (por omissão, false) CallbackContract especifica o contrato (tipo.net) de retorno numa comunicação duplex (two-way) (por omissão, null)... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 40
WCF Contratos Propriedades de OperationContract: Name especificao nomeassociadoaoelementowsdl:operation name na definição de PortType. Por omissão, o nome do método. Action especifica a acção (elemento wsdl:input wsaw:action na definição de PortType) que identifica unicamente esta operação. Por omissão a concatenação do namespace do contrato, do nome do contrato (interface) do nome da operação e da string Response se a mensagem for uma resposta. Pode ser * para redireccionar para esta operação todas as mensagens recebidas mas que não podem ser associadas a uma operação determinada (mensagens desconhecidas). ReplyAction idem para mensagem de reply. Se for * no servico indica que não pretendemos gerar mensagens de reply. No cliente, um * indica ao WCF para não validar a reply action. IsOneWay indica se esta operação não produz qualquer mensagem de resposta (por omissão, false). Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 41 WCF Contratos Operação One-Way [ServiceContract] public interface IServicoContas [OperationContract] float obtersaldo(int numero); [OperationContract] void alterarsaldo(int numero, float s); [OperationContract(IsOneWay = true)] void x(); // tem de ser void e sem parâmetros ref ou out Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 42
WCF Contratos Operação One-Way public class ServicoContas : IServicoContas public float obtersaldo(int numero) public void alterarsaldo(int numero, float s) public void x() Thread.Sleep(5000); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 43 WCF Contratos Operação One-Way No cliente: class Cliente static void Main(string[] args) // para hospedeiro nosso: ChannelFactory<IServicoContas> servico = new ChannelFactory<IServicoContas>( ); IServicoContas endpt = servico.createchannel(); endpt.x(); retorno imediato Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 44
WCF Contratos Operação duplex Pode ser Request-Response ou One-Way É criado um novo canal para o sentido contrário (com o mesmo protocolo) se o protocolo não o suportar (p. ex: http) O endereço no sentido contrário pode ser definido, mas, caso não o seja, é determinado com base no endereço de rede de onde o serviço é chamado. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 45 WCF Contratos Operação duplex: o serviço namespace ServicoDuplex [ServiceContract(CallbackContract=typeof(IClienteCallback))] public interface IServico [OperationContract] void LigaMe(); [ServiceContract] public interface IClienteCallback [OperationContract] void EstouAligarTe(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 46
WCF Contratos Operação duplex: o serviço public class Servico : IServico public void LigaMe() IClienteCallback c = Permite acesso a informação sobre o contexto se execução de uma operação dum serviço Informação sobre a thread corrente OperationContext.Current.GetCallbackChannel<IClienteCallback>(); ChamadaCliente chcli = new ChamadaCliente(c); Thread t = new Thread( new ThreadStart(chCli.Chamar)); t.isbackground = true; t.start(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 47 WCF Contratos Operação duplex: o serviço public class ChamadaCliente private IClienteCallback cli; public ChamadaCliente(IClienteCallback c) cli = c; public void Chamar() for(int i = 0; i < 10; ++i) cli.estoualigarte(); Thread.Sleep(5000); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 48
WCF Contratos Operação duplex: o serviço public class Host // Hospedeiro public static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 49 WCF Contratos Operação duplex: o serviço <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicoduplex.servico behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="http://localhost:8000/servicoduplex"/> </baseaddresses> </host> <endpoint address="" binding = "wsdualhttpbinding" contract="servicoduplex.iservico"/> <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 50
WCF Contratos Operação duplex: o serviço <behaviors> <servicebehaviors> <behavior name="sb"> <servicemetadata httpgetenabled="true"/> </behavior> </servicebehaviors> </behaviors> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 51 WCF Contratos Operação duplex: o cliente (sem ajudas) [ServiceContract(CallbackContract = typeof(iclientecallback))] public interface IServico [OperationContract] void LigaMe(); [ServiceContract] public interface IClienteCallback [OperationContract] void EstouAligarTe(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 52
WCF Contratos Operação duplex: o cliente (sem ajudas) namespace ClienteDuplexSemAddServRef public class HandlerCallbackCliente : IClienteCallback public void EstouAligarTe() Console.WriteLine("Ligaram-me"); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 53 WCF Contratos Operação duplex: o cliente (sem ajudas) Fornece contexto de execução de uma instância de um serviço static void Main(string[] args) InstanceContext site = new InstanceContext( Objecto que implementa a instância do serviço new HandlerCallbackCliente()); // Assim para configuracao em código: //WSDualHttpBinding binding = new WSDualHttpBinding(); //binding.clientbaseaddress = // new Uri("http://localhost:8001/Cliente/"); //servico = //new DuplexChannelFactory<IServico>( // site, // binding, // new EndpointAddress("http://localhost:8000/ServicoDuplex") // ); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 54
WCF Contratos Operação duplex: o cliente (sem ajudas) // ou assim, para configuraçao em app.config: DuplexChannelFactory<IServico> servico = new DuplexChannelFactory<IServico>(site, "clienteservico"); IServico endpt = servico.createchannel(); endpt.ligame(); Console.WriteLine("Enter para terminar"); Console.ReadLine(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 55 WCF Contratos Operação duplex: o cliente (sem ajudas) A configuração: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <client> <endpoint name="clienteservico" address ="http://localhost:8000/servicoduplex" binding="wsdualhttpbinding" contract="iservico" bindingconfiguration= MeuBindingDuplexCliente"/> </client> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 56
WCF Contratos Operação duplex: o cliente (sem ajudas) A configuração: <bindings> <wsdualhttpbinding> <binding name="meubindingduplexcliente" clientbaseaddress="http://localhost:8001/cliente/" > <security mode="message"> <message clientcredentialtype="windows" negotiateservicecredential="true" algorithmsuite="default" /> </security> </binding> </wsdualhttpbinding> </bindings> </system.servicemodel> </configuration> Se não for indicado, é usado um endereço baseado no endereço da máquina que invocou o serviço e com o memso porto Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 57 WCF Contratos Operação duplex: o cliente (com Add Service Reference) using ClienteDuplex.ServiceReference1; namespace ClienteDuplex public class HandlerCallbackCliente: IServicoCallback public void EstouAligarTe() Console.WriteLine("Ligaram-me"); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 58
WCF Contratos Operação duplex: o cliente (com Add Service Reference) static void Main(string[] args) InstanceContext site = new InstanceContext(new HandlerCallbackCliente()); ServicoClient proxy = new ServicoClient(site); proxy.ligame(); Console.WriteLine("Enter para terminar"); Console.ReadLine(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 59 WCF Contratos Operação duplex: o cliente (com Add Service Reference)... <system.servicemodel> <bindings> <wsdualhttpbinding> <binding name="wsdualhttpbinding_iservico" clientbaseaddress="http://localhost:8001/cliente/" >...... </binding> </wsdualhttpbinding> </bindings> <client> <endpoint address="http://localhost:8000/servicoduplex" binding="wsdualhttpbinding" bindingconfiguration="wsdualhttpbinding_iservico" contract="servicereference1.iservico" name="wsdualhttpbinding_iservico"> <identity> Se não se indicar, é usado um endereço baseado no do serviço, portanto, com o memso porto Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 60
WCF Contratos Operação One-Way emparelhada versus Operação duplex Paired one-way Os contratos podem ter versões independentes. Os serviços podem ser oferecidos a outros clientes. Cada contrato one-way pode definir os seus próprios bindings e behavioirs Duplex Os callback do lado do cliente são determinados pelo serviço. Novas versões do serviço podem obrigar a alterações do cliente. Forte compromisso com situações onde o único consumidor das operações do cliente é o serviço. Os protocolos de comunicação são os mesmos em ambas as direcções porque dependem dos bindings do serviço Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 61 WCF Contratos Multiplos contratos no mesmo serviço: namespace ServicoMultiplosContratos [ServiceContract] public interface IServico1 [OperationContract] void op1(); [ServiceContract] public interface IServico2 [OperationContract] void op2(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 62
WCF Contratos Multiplos contratos no mesmo serviço: public class Servico : IServico1,IServico2 public void op1() Console.WriteLine("op1"); public void op2() Console.WriteLine("op2"); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 63 WCF Contratos Multiplos contratos no mesmo serviço: public class Host // Hospedeiro public static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 64
WCF Contratos Multiplos contratos no mesmo serviço: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicomultiploscontratos.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress= "http://localhost:8000/exemplomultiploscontratos"/> <add baseaddress= "net.tcp://localhost:8002/exemplomultiploscontratos"/> </baseaddresses> </host> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 65 WCF Contratos Multiplos contratos no memso serviço: <endpoint address="" name="ep1" binding = "basichttpbinding" contract="servicomultiploscontratos.iservico1"/> <endpoint address="adr2" name ="ep2" binding="nettcpbinding" contract ="ServicoMultiplosContratos.IServico1"/> <endpoint address="adr3" name ="ep3" binding="basichttpbinding" contract ="ServicoMultiplosContratos.IServico2"/> <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 66
WCF Contratos Multiplos contratos no mesmo serviço o cliente: using TesteServicoMultiplosContratos.ServiceReference1; namespace TesteServicoMultiplosContratos class Program static void Main(string[] args) //Servico1Client proxy1 = new Servico1Client(); // assim dá erro!!! Servico1Client proxy1 = new Servico1Client("ep1"); Servico1Client proxy2 = new Servico1Client("ep2"); Servico2Client proxy3 = new Servico2Client(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 67 WCF Contratos Multiplos contratos no mesmo serviço o cliente: Console.WriteLine("-----"); proxy1.op1(); Console.WriteLine("====="); proxy2.op1(); Console.WriteLine("*****"); proxy3.op2(); proxy1.close(); proxy2.close(); proxy3.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 68
WCF Contratos Alteração de nomes WSDL: Da forma como trabalhamos anteriormente, as descrições WSDL e, portanto, as mensagens trocadas com o serviço usam nomes derivados dos nomes das classes e interfaces utilizados. O (XML) namespace associado ao <porttype> do serviço também é por omissão igual a http://tempuri.org. Ora, este namespace apenas deve ser usado para desenvolvimento. Na exploração definitiva, cada organização deve usar os seus próprios target namespaces. Por outro lado, a exposição dos nossos nomes de codificação também pode não ser razoável, pois não permite ocultar aspectos internos da organização, como, por exemplo, standardas adoptados para a codificação de nomes. Quando usamos serviços desenvolvidos por outros, a obrigação de usarmos os nomes conatantes da definição WSDL também não é razoável. Por exemplo, impede-nos de usar standards de codificação internos da organização. O WCF permite-nos algum nível de controlo sobre estes aspectos Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 69 WCF Contratos Alteração de nomes WSDL: targetnamespace wsdl:service name Termo WSDL wsdl:portype namespace wsdl:porttype name wsdl:operation wsdl:input wsdl:output Atributo WCF Pode ser alterado com o atributo [ServiceBehavior(Namespace=...)] [ServiceBehavior(Name=...)] [ServiceContract(Namespace=...)] [ServiceContract(Name=...)] [OperationContract(Name=...)] [OperationContract(Action=..)] [OperationContract(ReplyAction=...)] Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 70
WCF Contratos Data Contracts: Como associar dados simples e complexos usados ao nível da programação do serviço a dados representados por esquemas XML (XSD) [DataContract] public class Conta [DataMember] public int Numero get; set; [DataMember] public string Titular get; set; public float Saldo get; set; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 71 WCF Contratos Data Contracts (representação XSD): <?xml version="1.0" encoding="utf-8"?> <xs:schema elementformdefault="qualified" targetnamespace="http://schemas.datacontract.org/2004/07/servico1" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:tns="http://schemas.datacontract.org/2004/07/servico1"> <xs:complextype name="conta"> <xs:sequence> <xs:element minoccurs="0" name="numero" type="xs:int" /> <xs:element minoccurs="0" name="titular" nillable="true" type="xs:string" /> </xs:sequence> </xs:complextype> <xs:element name="conta" nillable="true" type="tns:conta" /> </xs:schema> No caso concreto, aperecem por ordem alfabética No caso de haver hierarquias de tipos, são usados extension types (<xs:extention>) em XSD Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 72
WCF Contratos <s:envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:header> <To s:mustunderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://localhost:8000/servico1 </To> <Action s:mustunderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://tempuri.org/iservico/inserirconta </Action> </s:header> <s:body> <inserirconta xmlns="http://tempuri.org/"> <c xmlns:a="http://schemas.datacontract.org/2004/07/servico1 xmlns:i="http://www.w3.org/2001/xmlschema-instance"> <a:numero>7777</a:numero> <a:titular>rita</a:titular> </c> </inserirconta> </s:body> </s:envelope> Mensagem soap resultante da serialização (por DataContractSerializer) para uma invocação da operação inserirconta(c). c é o nome do parâmetro no OperationContract Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 73 WCF Contratos O serializador DataContractSerializer expõe em wsdl (na forma de XSD) e serializa para soap tipos que obedeçam a uma das seguintes condições: 1.Estejam marcados com [DataContract] e [DataMember] 2.Estejam marcados com [CollectionDataContract] 3.Derivem de IXmlSerializable 4.Estejam marcados com [Serializable] (sem membros marcados com [NotSerializable]???) 5.Estejam marcados com [Serializable] e implementem ISerializable 6.Sejam tipos primitivos CLR (int32, string, ) 7.Sejam dos tipos arrays de bytes, DateTime, DateTimeOffset, TimeSpan, Guid, Uri, XmlQualifiedName, XmlElement e XmlNode 8.Sejam arrays e colecções dos tipos List<T>, Dictionary<K,V> e Hashtable 9.Sejam Enumerados 10.Sejam dos tipos ADO.NET DataTable e DataSet Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 74
WCF Contratos Data Contracts (colecções): Não existe uma definição XSD ou WSDL standard equivalente às colecções CLR (IEnumerable<T>). Assim, estes objectos são todos representados da mesma forma. São, por isso, consumidos no cliente sempre como arrays. No entanto, se no membro de um DataContract indicarmos outro tipo de colecção (List, ArrayList, LinkedList, ), a desserialização fará essa conversão se o indicarmos quando importamos o esquema XSD (através da propriedade ImportOptions de XsdDataContractImporter). No visual studio, isso é feito em Add Service Reference e Configure Service Reference, pois podemos indicar como queremos que esses membros sejam tratados. Ver também o atributo [CollectionDataContract] Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 75 WCF Contratos Data Contracts (colecções): [ServiceContract] public interface IServico [OperationContract] Conta obterconta(int numero); [OperationContract] List<Conta> obtercontas(list<int> numeros); É importado através do serviço de mata-dados como: [ServiceContract] public interface IServico [OperationContract] Conta obterconta(int numero); [OperationContract] Conta[] obtercontas(int[] numeros); E, em termos de WSDL, teremos: Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 76
WCF Contratos Data Contracts (colecções): <xs:complextype name="conta"> </xs:complextype> <xs:element name="conta" nillable="true" type="tns:conta" /> <xs:complextype name="arrayofconta"> <xs:sequence> <xs:element minoccurs="0" maxoccurs="unbounded" name="conta" nillable="true" type="tns:conta" /> </xs:sequence> </xs:complextype> <xs:element name="arrayofconta" nillable="true type="tns:arrayofconta" /> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 77 WCF Contratos Data Contracts (colecções): No cliente: var contas = proxy.obtercontas(new List<int> 1, 3 ); dá origem à seguinte mensagem SOAP: <s:envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:header> <To s:mustunderstand="1 xmlns= "http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://localhost:8000/servico1 </To> <Action s:mustunderstand="1" xmlns= "http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://tempuri.org/iservico/obtercontas </Action> </s:header> Informação sobre endereçamento, segurança, transacções Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 78
WCF Contratos Data Contracts (colecções): <s:body> <obtercontas xmlns="http://tempuri.org/"> <numeros xmlns:a= "http://schemas.microsoft.com/2003/10/serialization/arrays" xmlns:i="http://www.w3.org/2001/xmlschema-instance"> <a:int>1</a:int> <a:int>3</a:int> </numeros> </obtercontas> </s:body> </s:envelope> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 79 WCF Contratos De notar que a descrição wsdl também inclui uma descrição XSD para definições dos parâmetros das operações (em http://localhost:8000/servico1?xsd=xsd0): <?xml version="1.0" encoding="utf-8"?> <xs:schema elementformdefault="qualified"...>... <xs:element name="obtercontas"> <xs:complextype> <xs:sequence> <xs:element minoccurs="0" name="numeros" nillable="true" type="q2:arrayofint xmlns:q2= "http://schemas.microsoft.com/2003/10/serialization/arrays" /> </xs:sequence> </xs:complextype> </xs:element> <xs:element name="obtercontasresponse"> <xs:complextype> <xs:sequence> <xs:element minoccurs="0" name="obtercontasresult" nillable="true" type="q3:arrayofconta" xmlns:q3= "http://schemas.datacontract.org/2004/07/servico1" /> </xs:sequence> </xs:complextype> </xs:element>... <wsdl:message name="iservico_obtercontas_inputmessage"> <wsdl:part name="parameters" element="tns:obtercontas" /> </wsdl:message> <wsdl:message name="iservico_obtercontas_outputmessage"> <wsdl:part name="parameters" element="tns:obtercontasresponse" /> </wsdl:message> Com base nesta descrição e na descrição XSD dos data contracts é possível desserializar as mensagens Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 80
WCF Contratos Também não esquecer: <wsdl:message name="iservico_obtercontas_inputmessage"> <wsdl:part name="parameters" element="tns:obtercontas" /> </wsdl:message> <wsdl:message name="iservico_obtercontas_outputmessage"> <wsdl:part name="parameters" element= <wsdl:porttype name="iservico"> "tns:obtercontasresponse" /> </wsdl:message> <wsdl:operation name="obtercontas"> <wsdl:input wsaw:action="http://tempuri.org/iservico/obtercontas message="tns:iservico_obtercontas_inputmessage" /> <wsdl:output wsaw:action="http://tempuri.org/iservico/obtercontasresponse" message="tns:iservico_obtercontas_outputmessage" /> </wsdl:operation> </wsdl:porttype> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 81 WCF Contratos Data contracts: Propriedades de DataContract: Name controla a propriedade name no elemento <xs:complextype> do XSD que define o tipo em termos de wsdl (por omissão, o nome qualificado da classe) Namespace idem, mas para a propriedade namespace (por omissão um nome derivado do Namespace CLR (Clr.Namespace): "http://schemas.datacontract.org/2004/07/clr.namespace")... Atenção: usar namespaces nos DataContracts Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 82
WCF Contratos Data contracts: Propriedades de DataMember: Name controla a propriedade name no elemento <xs:element> do XSD que define o tipo em termos de wsdl (por omissão o nome do membro CLR) EmitDefaultValue controla se deve ser serializado o valor por omissão do membro (por omissão, true). IsRequired Indica se o membro deve ou não estar presente no processo de desserialização (ver controlo de versões). (por omissão, false). Order o número de ordem do membro na stream de serialização. Os membros das classes base vêm primeiro, depois os da classe derivada não marcados com Order, por ordem alfabética e, por fim, os marcados com Order pela ordem definida e, dentro desta, por ordem alfabética (por omissão, order = -1).... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 83 WCF Contratos Data Contracts (known types): [DataContract] [KnownType(typeof(subClasse))] public class Classe Pode ser indicado ao nível do [OperationContract] com o atributo [ServiceKnownType], mas, neste caso, os tipos indicados podem apenas ser usados nas operações onde são indicados, ou em todas as operaçõees da interface se ServiceKnownType for usado ao nível da interface. [DataContract] public class SubClasse : Classe Se no destino apenas existir a classe Classe e chegar uma instância de SubClasse, a desserialização não consegue criar o objecto. Isto pode ocorrer se o cliente criar SubClasse e esta não existir no serviço. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 84
WCF Contratos Data Contracts: Em alternativa, podemos usar o nó <system.runtime.serialization> em App.config ou Web.config para indicar known types: <system.runtime.serialization> <datacontractserializer> <declaredtypes> <add type ="Classe, Minhadll, Version=1.0.0.0, Culture=neutral, PublickeyToken=null"> <knowntype type ="subclasse, MinhaDll, Version=1.0.0.0, Culture=neutral, PublickeyToken=null"/> </add> </declaredtypes> </datacontractserializer> </system.runtime.serialization> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 85 WCF Contratos Data Contracts: Podemos ainda gerar os known types dinamicamente: [DataContract] [KnownTypes( obterknowntypes )] public class Classe [DataMember] public int x; static Type[] obterknowntypes() return new Type[] typeof(subclasse), ; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 86
WCF Contratos Data Contracts (versões): O data contracts podem sofrer algumas alterações sem quebra de compatibilidade, tais como adição ou remoção de membros não marcados com IsRequired = true. Uma consequência positiva é que serviço e clientes podem evoluir independentemente uns dos outros (desde que se mantenha compatibilidade). Alterações com quebra de compatibilidade: Alteração das propriedades Name ou Namespace do data contract Alteração do nome ou remoção de um membro que estava marcado com IsRquired = true Adição de um novo membro com um nome usado anteriormente Alteração do tipo de dados de um data member Adição de novos membros marcados com IsRequired = true Alteração da propriedade IsRequired de um DataMember de false para true Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 87 WCF Contratos Data Contracts (versões): [DataContract] class Conta // versão 1 [DataMember] public int Numero get; set; [DataMember] public string Titular get; set; [DataContract] class Conta // versão 3 [DataMember(Name= Numero )] public int N get; set; [DataContract] class Conta // versão 2 [DataMember(Name= Numero )] public int N get; set; [DataMember] public string Titular get; set; versões compatíveis [DataMember((Order=0)] public int A get; set; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 88
WCF Contratos Data Contracts (round- trip em versões): [DataContract] public class Aluno // versão 1 [DataMember] public int Numero; [DataMember] public string Nome; [DataContract(Name= Aluno )] public class Aluno2 // versão 2 [DataMember] public int Numero; [DataMember] public string Nome; [DataMember(Order=3)] public string Telefone; call x(aluno(v2) a) Cliente usando Aluno versão 2 retorna a (mas a versão 1) Serviço usando Aluno versão 1 O que acontece ao membro Telefone? Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 89 WCF Contratos Data Contracts (round- trip em versões): [DataContract] public class Aluno : IExtensibleDataObject // versão 1 [DataMember] public int Numero; [DataMember] public string Nome; private ExtensionDataObject dadosextra; public virtual ExtensionDataObject ExtensionData get return dadosextra; set dadosextra = value; Lista com informação dos data members não conhecidos (estes membros serão serializados se uma instância deste data contract for enviada) [DataContract(Name= Aluno )] public class Aluno2 // versão 2 [DataMember] public int Numero; [DataMember] public string Nome; [DataMember(Order=0)] public string Telefone; Um serviço pode impedir este funcioamento através do atributo de comportamento Boa prática, mas não necessário Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 90
WCF Contratos Data Contracts (versões): Por omissão, muitas plataformas de serviços (incluindo o WCF) não fazem validação do esquema dos data contracts, permitindo, por isso, elementos extra não suportados pelo esquema. Nestes casos, os métodos que vimos para lidar com versões são adequados. Nos casos em que é necessário (ou as plataformas impõem) a validação de esquemas, a regra é definir um novo data contract com outro nome ou outro namespace (o recomendado) e proceder às alterações necessárias para definição da nova funcionalidade associada à nova versão no service contract. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 91 WCF Contratos Data Contracts (equivalência) Dois data contracts são equivalentes se tiveram o mesmo namespace e o mesmo nome e se cada data member num deles tiver um data member equivalente no outro. A ordem dos membros também tem de ser a mesma. Dois data members são equivalentes se tiverem o mesmo nome e o mesmo tipo de dados. Em suma, dois data contracts são equivalentes se gerarem a mesma descrição XSD. DataContract] public class Contacto [DataMember] public string Nome; [DataMember] public string Telefone; Data contracts equivalentes [DataContract(Name = "Contacto")] public class Pessoa [DataMember(Name = Nome")] private string NomeCompleto; private string address; [DataMember(Name = Telefone")] private string NumTel; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 92
WCF Contratos Data Contracts (equivalência) DataContract] public class Contacto [DataMember(Order=1)] public string Nome; [DataMember(Order=0)] public string Telefone; [DataContract(Name = "Contacto")] public class Pessoa [DataMember(Name = Nome")] private string NomeCompleto; private string address; [DataMember(Name = Telefone")] private string NumTel; Ordem alfabética: Nome < Telefone Data contracts não equivalentes Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 93 WCF Contratos Message Contracts Permitem trabalhar ao nível das mensagens SOAP. Não veremos este tipo de contratos. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 94
WCF Canais e Bindings Canais São definidos para o transporte de mensagens, protocolos e intercepção de mensagens. Funcionam agrupados em camadas. Aplicação Protocolo... Protocolo Transporte Os canais de protocolo permitem tratar aspectos de segurança, reliable messaging, transacções, etc. Não aprofundaremos o tema canais nestas notas Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 95 WCF Canais e Bindings Os bindings encapsulam a configuração de cenários de comunicação. Consistem de elementos que especificam como e quais canais estão organizados em stack. Aplicação Protocolo... Protocolo Transporte Channel stack Binding Element... Binding Element Binding Element Binding Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 96
WCF Canais e Bindings Um binding tem de incluir, obrigatoriamante: 1.Um elemento de binding para o transporte (canal de transporte) 2.Um elemento de binding para a codificação de mensagens (o qual pode ser fornecido por omissão pelo elemento de binding para transporte). Opcionalmente, pode incluir um número variável de elementos de binding para protocolos. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 97 WCF Canais e Bindings O WCF já fornece alguns bindings para cenários comuns: Binding Interoper. Modelo de segurança Sessão Transacções Duplex basichttpbinding Basic Profile 1.1 (None), Transport, Message, Mixed None, (None) (None) n/a wshttpbinding WS None, Transport, (Message), Mixed wsdualhttpbinding ws2007httpbinding (None), Transport, Reliable Session (None), Yes WS None, (Message) None, (Message) (None), Yes yes nettcpbinding.net None, (Transport), Message, Mixed netnamedpipebinding.net None, (Transport) netmsmqbinding.net None, Message, (Transport), Both Reliable Session, (Transport) None, (Transport) (None), Yes (None), Yes n/a yes yes (None) (None), Yes no Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 98
WCF Canais e Bindings Cada um dos bindings pré-definidos possui um conjunto de propriedades. Algumas destas propriedades são comuns a vários dos bindings (por exemplo, opentimeout), mas outras são específicas. Por exemplo, o nettcpbinding possui, entre outras as seguintes propriedades: closetimeout, maxconnections, name, portsharingenabled, opentimeout, receivetimeout, security, sendtimeout, transactionflow, transactionprotocol O netmsmqbinding possui, entre outras, as seguintes propriedades: closetimeout, customdeadletterqueue, deadletterqueue, Durable, exactlyonce, queuetransferprotocol, name, receivetimeout, security, sendtimeout, timetolive, useactivedirectory, usemsmqtracing, usesourcejournal As propriedades podem ser definidas por configuração (App.config ou Web.config) ou por programação. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 99 WCF Canais e Bindings start Adaptado de: Essential Windows Communication Foundation for.net Framework 3.5, Steve Resnick, Richard Crane, Chris Bowen, Micrsosoft.net Development Series, Addison-Wesley, 2008 Interoperab.? No local? Yes netnamedpipebinding Yes Interop. level? WS-* Duplex? Basic Yes basichttpbinding wsdualhttpbinding No Queuing? No Yes No legacy? netmsmqbinding Yes... No Federated security? No wshttpbinding/ ws2007httpbinding Peer? No nettcpbinding Yes... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 100 Yes...
WCF Canais e Bindings Desempenho: nº operações por segundo 8000 7000 6000 5000 4000 Execução de serviço e cliente na mesma máquina 3000 2000 1000 0 ws2007httpbinding wshttpbinding basichttpbinding nettcpbinding netnamedpipebinding Adaptado de: Essential Windows Communication Foundation for.net Framework 3.5, Steve Resnick, Richard Crane, Chris Bowen, Micrsosoft.net Development Series, Addison-Wesley, 2008 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 101 WCF Canais e Bindings As propriedades dos bindings podem ser definidas por programação: static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico), new Uri("net.tcp://localhost:8000/Servico")); NetTcpBinding bd = new NetTcpBinding(); bd.security.mode = SecurityMode.None; host.addserviceendpoint(typeof(iservico), bd, ""); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 102
WCF Canais e Bindings Mas, também por configuração: static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 103 WCF Canais e Bindings Mas, também por configuração: Em App.config: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servico.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8000/servico"/> <add baseaddress="http://localhost:8001/servico"/> </baseaddresses> </host> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 104
WCF Canais e Bindings Mas, também por configuração: Em App.config: <endpoint address="" binding = "nettcpbinding contract="servico.iservico" bindingconfiguration="nomemeubinding"/> <endpoint address = "mex binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <servicebehaviors> <behavior name="sb"> <servicemetadata httpgetenabled="true"/> </behavior> </servicebehaviors> </behaviors> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 105 WCF Canais e Bindings Mas, também por configuração: Em App.config: <bindings> <nettcpbinding> <binding name="nomemeubinding" closetimeout="00:01:00"> <security mode="none"> </security> </binding> </nettcpbinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 106
WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço: namespace ServicoMsmq [DataContract(Namespace = MeuNamespace")] public class Conta [DataMember(IsRequired = true)] public int Numero get; set; [DataMember(IsRequired = true)] public string Titular get; set; [DataMember(IsRequired = true)] public float Saldo get; set; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 107 WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço: [ServiceContract] public interface IServico [OperationContract(IsOneWay=true)] void inserirconta(conta c); [OperationContract(IsOneWay=true)] void alterarconta(conta c); public class Servico : IServico public void inserirconta(conta c) DataContext dc = new DataContext(...); Table<Conta> tc = dc.gettable<conta>(); tc.insertonsubmit(c); dc.submitchanges(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 108
WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço: public void alterarconta(conta c) DataContext dc = new DataContext(...); Table<Conta> tc = dc.gettable<conta>(); tc.attach(c, true); try dc.submitchanges(conflictmode.continueonconflict); catch (ChangeConflictException e) dc.changeconflicts.resolveall(refreshmode.keepcurrentvalues); dc.submitchanges(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 109 WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço: class Program static void Main(string[] args) if (!MessageQueue.Exists(@".\private$\filaWCF")) MessageQueue.Create(@".\private$\filaWCF", true); ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 110
WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço (App.config): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicomsmq.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.msmq://localhost/private/filawcf"/> <add baseaddress="http://localhost:8001/servico"/> </baseaddresses> </host> <endpoint address="" binding = "netmsmqbinding" contract="servicomsmq.iservico" bindingconfiguration="meubinding"/> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 111 WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço (App.config): <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <servicebehaviors> <behavior name="sb"> <servicemetadata httpgetenabled="true"/> </behavior> </servicebehaviors> </behaviors> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 112
WCF Canais e Bindings Exemplo com NetMsmqBinding: O serviço (App.config): <bindings> <netmsmqbinding> <binding name="meubinding"> <security mode="none"> </security> </binding> </netmsmqbinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 113 WCF Canais e Bindings Exemplo com NetMsmqBinding: O cliente: [ServiceContract] public interface IServico [OperationContract(IsOneWay = true)] void inserirconta(conta c); [OperationContract(IsOneWay = true)] void alterarconta(conta c); [DataContract(Namespace = MeuNamespace")] public class Conta [DataMember(IsRequired = true)] public int Numero get; set; [DataMember(IsRequired = true)] public string Titular get; set; [DataMember(IsRequired = true)] public float Saldo get; set; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 114
WCF Canais e Bindings Exemplo com NetMsmqBinding: O cliente: namespace ClienteMsmq class Program static void Main(string[] args) ChannelFactory<IServico> servico = new ChannelFactory<IServico>("clienteServico"); IServico endpt = servico.createchannel(); Conta c = new Conta Numero = 1, Titular = "msmq", Saldo = 0 ; endpt.alterarconta(c); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 115 WCF Canais e Bindings Exemplo com NetMsmqBinding: O cliente (App.config): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <client> <endpoint name="clienteservico" address ="net.msmq://localhost/private/filawcf" binding="netmsmqbinding" contract="iservico" bindingconfiguration="meubind"/> </client> <bindings> <netmsmqbinding> <binding name="meubind"> <security mode="none" /> </binding> </netmsmqbinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 116
WCF Canais e Bindings Custom bindings: Permitem criar bindings para situações não previstas pelos bindings pré-definidos. Por exemplo, protocolos de transporte específicos, formas específicas de segurança, etc. Podem ser criados por programação: static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico), new Uri("net.tcp://localhost:8000/Servico")); CustomBinding bd = new CustomBinding(); bd.elements.add(new BinaryMessageEncodingBindingElement()); bd.elements.add(new UdpBindingElement()); host.addserviceendpoint(typeof(iservico), bd, "");... Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 117 WCF Canais e Bindings Custom bindings: Mas, também podem ser criados por configuração: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servico.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8000/servico"/> </baseaddresses> </host> <endpoint address="" binding = custombinding" contract="servico.iservico" bindingconfiguration="nomemeubinding"/> </service> </services> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 118
WCF Canais e Bindings <bindings> <custombinding> <binding name="nomemeubinding" closetimeout="00:01:00"> <binarymessageencoding/> <udptransport/> </binding> </custombinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 119 WCF Canais e Bindings User-Defined bindings: Para novos bindings que sejam reutilizados em muitas aplicações pode ser preferível criá-los com base numa classe. Por exemplo, podemos criar uma classe que estenda NetTcpBinding e redefinir o método CreateBindingElements. Ou, podemos criar uma classe que estenda a classe Binding e redefinir o método CreateBindingElements. Desta forma teremos maior controlo sobre a implementação do binding. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 120
WCF Behaviors São classes que afectam a interacção entre clientes e serviços. São invocados, nuns casos, quando a execução do serviço (Host) e cliente se inicia, e, noutros casos, quando as mensagens fluem entre cliente e serviço. A classe ServiceHost é responsável pela definição de aspectos relacionados com o controlo de instâncias e de concorrência num serviço. Existem quatro tipos de behaviores: 1.Service behaviors: executam-se ao nível do serviço e aplicam-se a todos os endpoints. Controlam aspectos relacionados com o controlo de instâncias e características gerais do ponto de vista transaccional. 2.Endpoint behaviors: executam-se ao nível dos endpoints. Pemitem intercepção ao nível das mensagens. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 121 WCF Behaviors 3. Operation behaviors: executam-se ao nível das operações. São usados para controlar aspectos relacionados com serialização, fluxo transaccional, manipulação de parâmetros para as operações, etc. 4. Contract behaviors: especificam requisitos dos bindings para o serviço ou cliente. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 122
WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) O controlo de instâncias permite determinar quantas instâncias da classe que implementa o serviço podem coexistir na execução de operações do serviço. Controla-se pela propriedade InstanceContextMode do atributo [ServiceBehavior], a qual pode tomar os seguintes valores: Single: Apenas uma instância da classe para tratar todos os pedidos (singlenton). PerCall: Uma instância da classe por cada pedido. PerSession: Uma instância da classe por sessão de cliente. Se não se usarem canais com suporte a sessões, comporta-se como em PerCall Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 123 WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) O controlo de concorrência permite definir quantas threads (associadas a pedidos de clientes) podem estar, no máximo, a executar operações sobre uma das instâncias da classe que implementa o serviço. Controla-se pela propriedade ConcurrencyMode do atributo [ServiceBahavior], a qual pode tomar os valores: Single: Apenas uma thread de cada vez acede à instância (fila de espera). Reentrant: Apenas uma thread acede à instância, mas essa thread pode executar uma chamada a outro serviço que chama o serviço original (ex: duplex). O lock é libertado no serviço original. Outros pedidos podem entrar Multiple: Várias threads podem aceder à instância. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 124
WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações de ConcurrencyMode InstanceContextMode: ConcurrencyMode igual a Single e InatanceContextMode igual a: Single: Uma única instância para servir todos os pedidos (singleton). Enquanto um serviço está a ser satisfeito os outro são colocados em fila de espera. Se o pedido invocar outro serviço que volte a invocar o serviço original é produzida uma situação de deadlock. PerCall: para bindings sem sesões ao nível de transporte, ConcurrencyMode não é relevante, pois cada pedido de cliente é satisfeito por uma instância própria da classe que implementa o serviço. Caso contrário, é usada a mesma thread para aceder às instâncias na mesma sessão PerSession: Cada sessão de cliente tem uma instância própria para servir todos os seus pedidos. Se o cliente realizar vários pedidos assincronos na sessão, enquanto um está a ser servido, os restantes serão colocados em fila de espera. Entre sessões diferentes existe concorrência sem partilha de instâncias Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 125 WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações de ConcurrencyMode InstanceContextMode: ConcurrencyMode igual a Reentrant e InstanceContextMode igual a: Single: Idem combinação Single/Single, mas se o serviço original chamar outro serviço, o lock é libertado na instância original. Se este último serviço invocado realizar uma chamada para o serviço original, esta chamada irá para a fila de espera como qualquer outra. É da responsabilidade do programador garantir que o estado da instância é consistente após as chamadas a outros serviços. PerCall: idem combinação Single/PerCall PerSession: Idem combinação Single/Persession, mas com alterações similares às descritas para a combinação Reentrant/Single, naturalmete, indo os pedidos de callback para a fila de espera da sessão respectiva. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 126
WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações de ConcurrencyMode InstanceContextMode: ConcurrencyMode igual a Multiple e InstanceContextMode igual a: Single: Apenas uma instância da classe que implementa o serviço é usada para satisfazer os pedidos dos clientes. Várias threads correspondentes a pedidos de clientes podem aceder em paralelo à instância. A protecção contra efeitos da concorrência é da responsabilidade do programador. PerCall: Cada instância é acedida por uma única thread PerSession: Uma instância da classe que implementa o serviço é criada para satisfazer todos os pedidos da mesma sessão. Não existe fila de espera associada à sessão, pelo que, se o cliente realizar vários pedidos assíncronos na mesma sessão, eles podem aceder em paralelo à instância. A protecção contra efeitos da concorrência na mesma sessão é da responsabilidade do programador. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 127 WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Exemplo: Porque se vão usar sessões namespace ServicoTesteConcInst [ServiceContract(SessionMode = SessionMode.Required)] // por omissão é Allowed public interface IServico [OperationContract(IsOneWay=true)] void teste(); [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.?, InstanceContextMode = InstanceContextMode.?)] public class Servico : IServico public Servico() Console.WriteLine("Criada inst. em " + System.DateTime.Now); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 128
WCF Behaviors public void teste() Console.WriteLine("Teste chamado em " + System.DateTime.Now+ " Thead "+Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); class Program static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 129 WCF Behaviors O cliente: namespace ClienteTesteConcInst class Program static void Main(string[] args) ServicoClient proxy = new ServicoClient(); for (int i=0; i < 5; ++i) proxy.teste(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 130
WCF Behaviors Resultados: Single/Single Criada inst. em 30-12-2008 18:50:50 Serviço iniciado. Enter para terminar Teste chamado em 30-12-2008 18:50:55 Thead 4 Teste chamado em 30-12-2008 18:50:59 Thead 4 Teste chamado em 30-12-2008 18:51:05 Thead 4 Teste chamado em 30-12-2008 18:51:10 Thead 4 Teste chamado em 30-12-2008 18:51:15 Thead 4 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 131 WCF Behaviors Resultados: Single/PerCall (c/ canal de transporte com sessões) Serviço iniciado. Enter para terminar Criada inst. em 30-12-2008 18:52:03 Teste chamado em 30-12-2008 18:52:03 Thead 4 Criada inst. em 30-12-2008 18:52:08 Teste chamado em 30-12-2008 18:52:08 Thead 4 Criada inst. em 30-12-2008 18:52:13 Teste chamado em 30-12-2008 18:52:13 Thead 4 Criada inst. em 30-12-2008 18:52:18 Teste chamado em 30-12-2008 18:52:18 Thead 4 Criada inst. em 30-12-2008 18:52:23 Teste chamado em 30-12-2008 18:52:23 Thead 4 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 132
WCF Behaviors Resultados: Single/PerCall (c/ canal de transporte sem sessões - basichttpbinding) Serviço iniciado. Enter para terminar Criada inst. em 06-01-2009 20:12:45 Teste chamado em 06-01-2009 20:12:45 Thead 3 Criada inst. em 06-01-2009 20:12:45 Teste chamado em 06-01-2009 20:12:45 Thead 4 Criada inst. em 06-01-2009 20:12:45 Teste chamado em 06-01-2009 20:12:45 Thead 5 Criada inst. em 06-01-2009 20:12:46 Teste chamado em 06-01-2009 20:12:46 Thead 6 Criada inst. em 06-01-2009 20:12:46 Teste chamado em 06-01-2009 20:12:46 Thead 7 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 133 WCF Behaviors Resultados: Single/PerSession Serviço iniciado. Enter para terminar Criada inst. em 30-12-2008 18:53:37 Teste chamado em 30-12-2008 18:53:37 Thead 4 Teste chamado em 30-12-2008 18:53:42 Thead 4 Teste chamado em 30-12-2008 18:53:47 Thead 4 Teste chamado em 30-12-2008 18:53:52 Thead 4 Teste chamado em 30-12-2008 18:53:57 Thead 4 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 134
WCF Behaviors Resultados: Multiple/Single Criada inst. em 30-12-2008 18:56:58 Serviço iniciado. Enter para terminar Teste chamado em 30-12-2008 18:57:03 Thead 4 Teste chamado em 30-12-2008 18:57:04 Thead 5 Teste chamado em 30-12-2008 18:57:04 Thead 6 Teste chamado em 30-12-2008 18:57:05 Thead 7 Teste chamado em 30-12-2008 18:57:05 Thead 8 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 135 WCF Behaviors Resultados: Multiple/PerCall Serviço iniciado. Enter para terminar Criada inst. em 30-12-2008 18:58:33 Teste chamado em 30-12-2008 18:58:33 Thead 4 Criada inst. em 30-12-2008 18:58:34 Teste chamado em 30-12-2008 18:58:34 Thead 5 Criada inst. em 30-12-2008 18:58:34 Teste chamado em 30-12-2008 18:58:34 Thead 6 Criada inst. em 30-12-2008 18:58:35 Teste chamado em 30-12-2008 18:58:35 Thead 7 Criada inst. em 30-12-2008 18:58:35 Teste chamado em 30-12-2008 18:58:35 Thead 8 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 136
WCF Behaviors Resultados: Multiple/PerSession Serviço iniciado. Enter para terminar Criada inst. em 30-12-2008 18:59:40 Teste chamado em 30-12-2008 18:59:40 Thead 4 Teste chamado em 30-12-2008 18:59:40 Thead 5 Teste chamado em 30-12-2008 18:59:41 Thead 6 Teste chamado em 30-12-2008 18:59:41 Thead 7 Teste chamado em 30-12-2008 18:59:42 Thead 8 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 137 WCF Behaviors Controlo de sessões Alguns canais suportam a noção de sessão, a qual permite relacionar mensagens diferentes numa conversação. Esta noção estende-se aos bindings, os quais, para além de aspectos específicos dos bindings usados, permitem associar uma instância de uma classe que implementa um serviço a uma sessão. Podemos controlar se um serviço admite, exige ou não permite session-based bindings através da propriedade SessionMode do atributo ServiceContractAttribute, cujos valores possíveis são: Allowed indica que o contrato admite sessões se o binding usado as usar Required indica que o contrato exige um binding que use sessões NotAllowed indica que o contrato exige um binding que possa funcionar sem sessões (isto é, com transporte baseado em datagramas) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 138
WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações InstanceContextMode e SessionMode: InstanceContextMode igual a Single e SessionMode igual a: NotAllowed: Se o canal suportar sessões é gerada uma excepção Allowed: É usado o singleton com ou sem sessão, consoante o canal suporte, ou não sessões Required: É usado o singleton na sessão criada. Se o canal não suportar sessões, é gerada ume excepção. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 139 WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações InstanceContextMode e SessionMode: InstanceContextMode igual a PerCall e SessionMode igual a: NotAllowed: Se o canal suportar sessões é gerada uma excepção. É usada uma instância para cada chamada Allowed: É usada uma instância para cada chamada, com ou sem sessão, consoante o canal suporte, ou não sessões Required: É usada uma instância por cada chamada na sessão criada. Se o canal não suportar sessões, é gerada ume excepção. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 140
WCF Behaviors Controlo de instâncias e concorrência (Service Behavior) Combinações InstanceContextMode e SessionMode: InstanceContextMode igual a PerSession e SessionMode igual a: NotAllowed: Se o canal suportar sessões é gerada uma excepção. É usada uma instância para cada chamada Allowed: É usada uma instância para cada sessão (canal) se o canal suportar sessões ou para cada chamada se o canal não suportar sessões Required: É usada uma instância por cada sessão (canal). Se o canal não suportar sessões, é gerada ume excepção. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 141 WCF Behaviors O atributo OperationContract possui as propriedades IsInitiating (true por omissão e IsTerminating (false por omissão) que permitem indicar que uma operação inicia ou termina sessões. O início de sessões pode ser realizado dos seguintes modos: 1. Invocando System.ServiceModel.ICommunicationObject.Open num canal retornado por System.ServiceModel.ChannelFactory.CreateChannel. 2. Invocando System.ServiceModel.ClientBase.Open num cliente gerado por Add Service Rererence ou por Svcutil.exe. 3. Invocando uma operação marcada com IsInitiating=true sobre qualquer tipo de objecto cliente WCF. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 142
WCF Behaviors A terminação de sessões pode ser realizada dos seguintes modos: 1. Invocando System.ServiceModel.ICommunicationObject.Close sobre um canal retornado por System.ServiceModel.ChannelFactory.CreateChannel. 2. Invocando System.ServiceModel.ClientBase.Close gerado por Add Service Rererence ou por Svcutil.exe. 3. Invocando uma operação marcada com IsTerminating=true sobre qualquer tipo de objecto cliente WCF. Quando a primeira operação é invocada, o objecto cliente WCF automaticamente abre o canal e inicia uma sessão. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 143 WCF Behaviors Transacções (Operation Behavior) Sem transaction flow: namespace ServicoSemTransFlow [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 144
WCF Behaviors Transacções (Operation Behavior) Sem transaction flow: Por omissão é Allowed. Mas para usarmos TransactionAutoComplete=false é necessário usar um binding que suporte sessões [ServiceContract(SessionMode=SessionMode.Required) ] public interface IServico [OperationContract] Conta obterconta(int numero); [OperationContract] void inserirconta(conta c); [OperationContract] void alterarconta(conta c); [OperationContract] void Transferir(int c1, int c2, float montante); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 145 WCF Behaviors Transacções (Operation Behavior) Sem transaction flow: ServiceBehavior( TransactionIsolationLevel=System.Transactions.IsolationLevel.ReadCommitted, TransactionTimeout="00:03:00", TransactionAutoCompleteOnSessionClose=false, //omissão ReleaseServiceInstanceOnTransactionComplete = true //omissão. )] public class Servico : IServico Obriga a ConcurrencyMode = Single, public Conta obterconta(int numero) se, pelo menos, uma das operações tiver transactionscoperequired = true public void inserirconta(conta c) public void alterarconta(conta c) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 146
WCF Behaviors Transacções (Operation Behavior) Obriga a instance mode = PerSession Sem transaction flow: [OperationBehavior(TransactionAutoComplete=false, // true omissão TransactionScopeRequired=true // false por omissão )] public void Transferir(int c1, int c2, float montante) OperationContext.Current.SetTransactionComplete(); Deve ser a última instrução. Preferir TransactionAutoComplete=true (votação implícita) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 147 WCF Behaviors Transacções (Operation Behavior) Sem transaction flow: class Program static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 148
WCF Behaviors Transacções (Operation Behavior) Sem transaction flow: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicosemtransflow.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8000/servico"/> <add baseaddress="http://localhost:8001/servico"/> </baseaddresses> </host> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 149 WCF Behaviors Transacções (Operation Behavior) Sem transaction flow (cliente): static void Main(string[] args) ChannelFactory<IServico> servico = new ChannelFactory<IServico>( "clienteservico"); IServico endpt = servico.createchannel(); endpt.transferir(1, 2, 555); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 150
WCF Behaviors Transacções (Operation Behavior) Sem transaction flow (cliente): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <client> <endpoint name="clienteservico" address ="net.tcp://localhost:8000/servico" binding="nettcpbinding" contract="iservico bindingconfiguration="meubind"/> </client> <bindings> <nettcpbinding> <binding name="meubind" closetimeout="00:01:00"> <security mode="none"/> </binding> </nettcpbinding> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 151 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 1): namespace ServicoComTrFlow_1 [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 152
WCF Behaviors Transacções (Operation Behavior) Necessário para usar TransactionFlow Com transaction flow (serviço 1): [ServiceContract(SessionMode = SessionMode.Required)] public interface IServico [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] void alterarsaldo(int nc, float novosaldo); Também existe a classe TransactionFlowBindingElement para controlar o fluxo transaccional ao nível do endpoint Possibilidades: NotAllowed (omissão) não é permitido fazer fluir a transacção (o serviço não pode receber a transacção na mensagem SOAP) Allowed a transacção pode fluir (o cliente pode ou não fazer fluir a sua transacção e o serviço pode ou não usar um binding que suporte o fluxo de transacções). Exige IsOneWay=false no OperationContract Mandatory o serviço e o cliente devem usar um binding que suporte o fluxo de transacções. Ao serviço deve sempre chegar uma transacção do cliente. Exige IsOneWay=false no OperationContract Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 153 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 1): public class Servico : IServico [OperationBehavior(TransactionAutoComplete = true, //omissão TransactionScopeRequired = true, TransactionIsolationLevel= System.Transactions.IsolationLevel.Unspecified, )] // [TransactionFlow ] também pode ficar aqui public void alterarsaldo(int nc, float novosaldo) TransactionInformation info = Transaction.Current.TransactionInformation; Console.WriteLine("ID Tr. Distr: 0.", info.distributedidentifier); Console.WriteLine( Estado Tr: 0.", info.status); Usar Unspecified com traansaction flow para o serviço usar o nível de isolamento do cliente Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 154
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço1): class Program static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 155 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 1): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicocomtrflow_1.servico behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8000/servico"/> <add baseaddress="http://localhost:8001/servico"/> </baseaddresses> </host> <endpoint address="" binding = "nettcpbinding" contract="servicocomtrflow_1.iservico" bindingconfiguration="meubinding"/> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 156
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 1): <bindings> <nettcpbinding> <binding name="meubinding" transactionflow="true"> <security mode="none"/> </binding> </nettcpbinding> </bindings> </system.servicemodel> </configuration> O binding tem de suportar transaction flow Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 157 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta [ServiceContract(SessionMode = SessionMode.Required)] public interface IServico [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] void alterarsaldo(int nc, float novosaldo); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 158
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): namespace ServicoComTrFlow_2 public class Servico : IServico [OperationBehavior(TransactionAutoComplete = true, //omissão TransactionScopeRequired = true )] public void alterarsaldo(int nc, float novosaldo) // código para alterar o saldo // chamar serviço 3 ChannelFactory<IServico> servico3 = new ChannelFactory<IServico>("clienteServico3"); IServico endpt3 = servico3.createchannel(); endpt3.alterarsaldo(3, -1); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 159 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): class Program static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 160
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <client> <endpoint name="clienteservico3" address ="net.tcp://localhost:8004/servico" binding="nettcpbinding" contract="iservico" bindingconfiguration="meubinding"/> </client> <services> <service name="servicocomtrflow_2.servico behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8002/servico"/> <add baseaddress="http://localhost:8003/servico"/> </baseaddresses> </host> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 161 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): <endpoint address="" binding = "nettcpbinding" contract="iservico" bindingconfiguration="meubinding"/> <endpoint address = "mex" binding = "mexhttpbinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <servicebehaviors> <behavior name="sb"> <servicemetadata httpgetenabled="true"/> </behavior> </servicebehaviors> </behaviors> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 162
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 2): <bindings> <nettcpbinding> <binding name="meubinding" transactionflow="true"> <security mode="none"/> </binding> </nettcpbinding> </bindings> </system.servicemodel> </configuration> Binding partilhado pelas partes cliente e serviço Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 163 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 3): namespace ServicoComTrFlow_3 [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta [ServiceContract(SessionMode = SessionMode.Required) ] public interface IServico [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] void alterarsaldo(int nc, float novosaldo); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 164
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 3): public class Servico : IServico [OperationBehavior(TransactionAutoComplete = true, //omissão TransactionScopeRequired = true )] public void alterarsaldo(int nc, float novosaldo) // código para alterar o saldo Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 165 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 3): class Program static void Main(string[] args) ServiceHost host = new ServiceHost(typeof(Servico)); host.open(); Console.WriteLine("Serviço iniciado. Enter para terminar"); Console.ReadLine(); host.close(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 166
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 3): <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <services> <service name="servicocomtrflow_3.servico" behaviorconfiguration="sb"> <host> <baseaddresses> <add baseaddress="net.tcp://localhost:8004/servico"/> <add baseaddress="http://localhost:8005/servico"/> </baseaddresses> </host> <endpoint address="" binding = "nettcpbinding" contract="servicocomtrflow_3.iservico" bindingconfiguration="meubinding"/> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 167 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (serviço 3): <bindings> <nettcpbinding> <binding name="meubinding" transactionflow="true"> <security mode="none"/> </binding> </nettcpbinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 168
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (cliente): [ServiceContract(SessionMode = SessionMode.Required)] public interface IServico [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] void alterarsaldo(int nc, float novosaldo); [DataContract(Namespace = "MeuNamespace")] public class Conta Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 169 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (cliente): namespace ClienteComTrFlow class Program static void Main(string[] args) ChannelFactory<IServico> servico = new ChannelFactory<IServico>("clienteServico"); IServico endpt = servico.createchannel(); ChannelFactory<IServico> servico1 = new ChannelFactory<IServico>("clienteServico1"); IServico endpt1 = servico1.createchannel(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 170
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (cliente): using (TransactionScope tr = new TransactionScope()) endpt.alterarsaldo(1, 0); endpt1.alterarsaldo(2, 0); tr.complete(); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 171 WCF Behaviors Transacções (Operation Behavior) Com transaction flow (cliente): <configuration> <system.servicemodel> <client> <endpoint name="clienteservico" address ="net.tcp://localhost:8000/servico" binding="nettcpbinding" contract="iservico" bindingconfiguration="meubind"/> <endpoint name="clienteservico1" address ="net.tcp://localhost:8002/servico" binding="nettcpbinding" contract="iservico" bindingconfiguration="meubind"/> </client> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 172
WCF Behaviors Transacções (Operation Behavior) Com transaction flow (cliente): <bindings> <nettcpbinding> <binding name="meubind" transactionflow="true"> <security mode="none"/> </binding> </nettcpbinding> </bindings> </system.servicemodel> </configuration> Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 173 ReleaseServiceInstanceOnTransactionComplete WCF Behaviors Transacções (Operation Behavior) Quando se tem ReleaseServiceInstanceOnTransactionComplete = true, o modo de instância mais adequado é o PerCall. Neste caso, Cada método vota no fim para a terminação da transacção (por exemplo, com TransactionAutoComplete = true). No entanto, se escolhermos o modo de instância PerSession (omissão), mantendo as características anteriores (ReleaseServiceInstanceOnTransactionComplete = true e votação no fim de cada método) o comportamento continua idêntico a PerCall, dado que cada instância é desactivada quando vota na terminação da transacção. Porém, é possível ter comportamentos transaccionais Session e Statefull se algumas operações não votarem na terminação das transacções: Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 174
WCF Behaviors Transacções (Operation Behavior) namespace ServicoTrSessao [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta [ServiceContract(SessionMode = SessionMode.Required) ] // Required necessário para se poder usar TransactionAutoComplete=false e // OperationContext.Current.SetTransactionComplete) public interface IServico [OperationContract(IsInitiating=true, IsTerminating=false)] void alterarconta(int nc, float valor); [OperationContract(IsTerminating=true,IsInitiating=false)] void Finalizar(); Não é necessário isto se Finalizar estiver marcado com Autocomplete a true e as outras operações com false Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 175 ReleaseServiceInstanceOnTransactionComplete WCF Behaviors Transacções (Operation Behavior) [ServiceBehavior( TransactionIsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, TransactionAutoCompleteOnSessionClose = false, ReleaseServiceInstanceOnTransactionComplete = true, //omissão InstanceContextMode = InstanceContextMode.PerSession, //omissão ConcurrencyMode = ConcurrencyMode.Single, // omissão IncludeExceptionDetailInFaults=true )] public class Servico : IServico private int nc1, nc2; private float v1, v2; Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 176
ReleaseServiceInstanceOnTransactionComplete WCF Behaviors Transacções (Operation Behavior) [OperationBehavior(TransactionAutoComplete = false, TransactionScopeRequired = true )] public void alterarconta(int nc, float valor) if (nc1 == 0) nc1 = nc; v1 = valor; else nc2 = nc; v2 = valor; false => afinidade transacçãoinstância (a 1ª transacção que acede à instância mantém-na até ao fim da sessão, não sendo possíveis outras transacções aceder à instância. Importante, por exemplo, quando existe propagação de transacções e um cliente usa TransactionScope de forma encadeada com RequiresNew, invocando operações na mesma sessão, mas com transacções diferentes. Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 177 WCF Behaviors Transacções (Operation Behavior) [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true )] public void Finalizar() DataContext dc = new DataContext( ); Table<Conta> tc = dc.gettable<conta>(); var conta1 = (from c in dc.gettable<conta>() where c.numero == nc1 select c).singleordefault(); var conta2 = (from c in dc.gettable<conta>() where c.numero == nc2 select c).singleordefault(); conta1.saldo += v1; conta2.saldo += v2; dc.submitchanges(); //throw new Exception(); // aborta a transacção Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 178
WCF Behaviors Transacções (Operation Behavior) O mesmo pode ser conseguido com: [ServiceBehavior( TransactionAutoCompleteOnSessionClose = true, )] public class Servico : IServico [OperationBehavior(TransactionAutoComplete = false, TransactionScopeRequired = true )] public void Finalizar() Se a sessão terminar sem erros, tenta-se completar (terminar com sucesso) a transacção Notar a diferença para o caso anterior Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 179 WCF Behaviors Transacções (Operation Behavior) O cliente: [ServiceContract(SessionMode = SessionMode.Required)] public interface IServico [OperationContract(IsInitiating = true, IsTerminating = false)] void alterarconta(int nc, float valor); [OperationContract(IsTerminating = true, IsInitiating = false)] void Finalizar(); [DataContract(Namespace = "MeuNamespace")] public class Conta Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 180
WCF Behaviors Transacções (Operation Behavior) O cliente: static void Main(string[] args) ChannelFactory<IServico> servico = new ChannelFactory<IServico>("clienteServico"); IServico endpt = servico.createchannel(); endpt.alterarconta(1,-555); // inicia sessão endpt.alterarconta(2, 555); endpt.finalizar(); // termina sessão e transacção Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 181 WCF Behaviors Transacções (Operation Behavior) SessionLess: namespace ServicoTrComMSMQ [DataContract(Namespace = "MeuNamespace")] [Table(Name = "Contas")] public class Conta [ServiceContract(SessionMode = SessionMode.NotAllowed)] public interface IServicoMSMQ [OperationContract(IsOneWay=true)] void inserirconta(conta c); [OperationContract(IsOneWay=true)] void alterarconta(conta c); também com Allowed temos sessionless Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 182
WCF Behaviors Transacções (Operation Behavior) SessionLess: Com SessionMode igual a Allowed e NotAllowed, também pode ser PerSession e Single. [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)] public class Servico : IServicoMSMQ [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true )] public void alterarconta(conta c) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 183 WCF Behaviors Transacções (Operation Behavior) SessionLess (cliente): A fila é transaccional => alinhamento é automático Sessionless => uma mensagem por operação (No serviço uma instância e uma transacção para cada chamada) IServicoMSMQ endpt = servico.createchannel(); Conta c = new Conta Numero = 1, Titular = "msmq1", Saldo = 0 ; using(transactionscope ts = new TransactionScope()) endpt.alterarconta(c); Conta c2 = new Conta Numero = 2, Titular = "msmq2", Saldo = 0 ; endpt.alterarconta(c2); ts.complete(); Conta c3 = new Conta Numero = 2, Titular = "msmq2", Saldo = 0 ; sem transacção distribuída (transacção MSMQ) endpt.alterarconta(c3); Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 184
WCF Behaviors Transacções (Operation Behavior) SessionFull: [ServiceContract(SessionMode = SessionMode.Required)] public interface IServicoMSMQ [OperationContract(IsOneWay=true, IsInitiating=true, IsTerminating = false)] void inserirconta(conta c); [OperationContract(IsOneWay=true, IsInitiating = true, IsTerminating = false)] void alterarconta(conta c); [OperationContract(IsOneWay=true, IsInitiating = false, IsTerminating = true)] void Finalizar(); Não é necessário isto se Finalizar estiver marcado com Autocomplete a true e os outros métodos com false (mas com o MSMQ) é necessário, pois o controlo feito só com TransactionAutoCompleteOnSessionClose=true não é suficiente (ver slide seguinte) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 185 WCF Behaviors Transacções (Operation Behavior) SessionFull: sessionfull - uma unica instancia para tratar todos os pedidos (mas um a um) [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession, //TransactionAutoCompleteOnSessionClose=true // Com O MSMQ só assim não dá )] public class Servico : IServicoMSMQ [OperationBehavior(TransactionAutoComplete = false, // transaction affinity TransactionScopeRequired = true )] public void alterarconta(conta c) Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 186
WCF Behaviors Transacções (Operation Behavior) SessionFull: [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true )] public void Finalizar() // não faz nada: é só para terminar a sessão e a transacção Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 187 WCF Behaviors Transacções (Operation Behavior) SessionFull (o cliente): Todas as chamadas são enviadas na mesma mensagem (No servidor são executadas uma a uma, mas mantendo a instância, logo, estado) IServicoMSMQ endpt = servico.createchannel(); Conta c = new Conta Numero = 1, Titular = "msmq1", Saldo = 0 ; using(transactionscope ts = new TransactionScope()) endpt.alterarconta(c); Conta c2 = new Conta Numero = 2, Titular = "msmq2", Saldo = 0 ; endpt.alterarconta(c2); endpt.finalizar(); servico.close(); ts.complete(); tem de se fachar o canal (sessão) antes de terminar a transacção, pois o fecho de sessão com transacções obriga a aceder à transacção ambiente corrente Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 188
Bibliografia Programming WCF Services, Juval Lowy, O'Reilly Pub, 2007 Essential Windows Communication Foundation for.net Framework 3.5, Steve Resnick, Richard Crane, Chris Bowen, Micrsosoft.net Development Series, Addison-Wesley, 2008 Arquitectura de Sistemas de Informação (ISEL-DEETC Walter Vieira) 189