Tuesday 15 May 2018

Estratégia de versionamento wcf


Estratégia de versionamento wcf
Esta é uma boa e uma pergunta complicada. O tópico de design de URI é ao mesmo tempo a parte mais proeminente de uma API REST e, portanto, um compromisso potencialmente de longo prazo com os usuários dessa API.
Como a evolução de um aplicativo e, em menor extensão, de sua API é um fato da vida e é até similar à evolução de um produto aparentemente complexo como uma linguagem de programação, o design de URI deve ter menos restrições naturais e deve ser preservado ao longo do tempo . Quanto maior o tempo de vida do aplicativo e da API, maior o comprometimento com os usuários do aplicativo e da API.
Por outro lado, outro fato da vida é que é difícil prever todos os recursos e seus aspectos que seriam consumidos por meio da API. Felizmente, não é necessário projetar a API inteira que será usada até o Apocalypse. É suficiente definir corretamente todos os endpoints de recursos e o esquema de endereçamento de cada recurso e instância de recurso.
Com o tempo, você pode precisar adicionar novos recursos e novos atributos a cada recurso específico, mas o método que os usuários da API seguem para acessar determinados recursos não deve ser alterado quando um esquema de endereçamento de recursos se tornar público e, portanto, final.
Este método se aplica à semântica do verbo HTTP (por exemplo, PUT deve sempre atualizar / substituir) e códigos de status HTTP que são suportados em versões anteriores da API (eles devem continuar a funcionar para que os clientes da API que trabalharam sem intervenção humana possam continuar trabalhando) Curtiu isso).
Além disso, como a incorporação da versão da API na URI interromperia o conceito de hipermídia como o mecanismo do estado do aplicativo (declarado na dissertação de doutorado de Roy T. Fieldings) por ter um endereço de recurso / URI que mudaria com o tempo, concluiria que a API As versões não devem ser mantidas em URIs de recursos por um longo tempo, o que significa que os URIs de recursos dos quais os usuários da API podem depender devem ser permalinks.
Claro, é possível incorporar a versão da API no URI de base, mas apenas para usos razoáveis ​​e restritos, como a depuração de um cliente de API que funciona com a nova versão da API. Essas APIs com versão devem ser limitadas no tempo e estar disponíveis apenas para grupos limitados de usuários da API (como durante betas fechados). Caso contrário, você se compromete onde não deveria.
Algumas considerações sobre a manutenção de versões da API com data de expiração. Todas as plataformas / linguagens de programação comumente usadas para implementar serviços da Web (Java, PHP, Perl, Rails, etc.) permitem uma vinculação fácil dos pontos de extremidade de serviço da Web a um URI de base. Dessa forma, é fácil reunir e manter uma coleção de arquivos / classes / métodos separados em diferentes versões da API.
A partir do POV dos usuários da API, também é mais fácil trabalhar e vincular-se a uma determinada versão da API quando isso é óbvio, mas apenas por tempo limitado, ou seja, durante o desenvolvimento.
A partir do POV do desenvolvedor da API, é mais fácil manter diferentes versões da API em paralelo usando sistemas de controle de origem que trabalham predominantemente em arquivos como a menor unidade de versão (código-fonte).
No entanto, com as versões da API claramente visíveis no URI, há uma ressalva: também é possível objetar essa abordagem, já que o histórico da API se torna visível / aparente no design da URI e, portanto, está sujeito a alterações ao longo do tempo que contraria as diretrizes do REST. Concordo!
A maneira de contornar essa objeção razoável é implementar a versão mais recente da API sob URI de base da API sem versão. Nesse caso, os desenvolvedores de clientes da API podem optar por:
desenvolver contra o mais recente (comprometendo-se a manter o aplicativo protegendo-o de eventuais alterações de API que possam quebrar seu cliente de API mal projetado).
ligar a uma versão específica da API (que se torna aparente), mas apenas por um tempo limitado.
Por exemplo, se a API v3.0 for a versão mais recente da API, as duas seguintes devem ser aliases (ou seja, devem comportar-se de forma idêntica a todas as solicitações da API):
Além disso, os clientes da API que ainda tentam apontar para a API antiga devem ser informados para usar a versão da API anterior mais recente, se a versão da API que eles estiverem usando for obsoleta ou não for mais suportada. Então, acessando qualquer um dos URIs obsoletos como estes:
deve retornar um dos 30 códigos de status HTTP que indicam o redirecionamento usado em conjunto com o cabeçalho HTTP de local que redireciona para a versão apropriada do URI de recurso que permanece como esta:
Existem pelo menos dois códigos de status HTTP de redirecionamento que são apropriados para cenários de versão de API:
301 Movido permanentemente, indicando que o recurso com um URI solicitado é movido permanentemente para outro URI (que deve ser um permalink de instância de recurso que não contém informações sobre a versão da API). Esse código de status pode ser usado para indicar uma versão de API obsoleta / sem suporte, informando ao cliente de API que um URI de recurso com versão foi substituído por um link permanente de recurso.

Versão de Serviço SOA - Melhores Práticas.
Sumário executivo.
Este documento tem como objetivo destacar algumas das melhores práticas relacionadas ao controle de versão de serviços em SOA. Essas práticas recomendadas são baseadas em problemas práticos que Torry Harris enfrentou ao implementar projetos SOA.
O controle de versão é um dos aspectos importantes da governança de SOA. Poucas estratégias de governança recomendam ter uma versão de linha de base do serviço para evitar a complexidade das versões. Por outro lado, poucas outras estratégias de governança preferem usar várias versões do mesmo serviço para que as alterações e aprimoramentos na interface de serviço não afetem os consumidores existentes. Este documento tem como objetivo destacar os prós e contras de cada abordagem e propõe as melhores práticas adequadas aos casos.
A solução técnica real para a implementação de versões de serviço é considerada fora do escopo deste documento, pois há várias abordagens simples e específicas do fornecedor. O foco deste documento é descrever o princípio de versão de serviço e destacar as melhores práticas.
Por que fazer o controle de versão?
Visão geral de versão de serviço.
A versão de serviço é a abordagem seguida pelos desenvolvedores de serviços para permitir que várias versões do mesmo serviço estejam operacionais ao mesmo tempo. Para dar uma analogia, qualquer biblioteca API de software reutilizável tem várias versões usadas por diferentes aplicativos. A mesma analogia se aplica aos serviços.
Exemplo de versão de serviço.
Serviços da Web são a maneira ideal de implementar serviços SOA. O diagrama a seguir ilustra o conceito de várias versões ativas com uma exibição dos serviços e a dependência de seus aplicativos de consumidor. No exemplo, há dois serviços - Serviço do Processador de Ordens e Serviço de Consulta de Estoque. Várias versões ativas existem para esses dois serviços. O diagrama mostra o caminho de dependência de sete aplicativos diferentes usando várias versões desses dois serviços.

Práticas recomendadas: versão de contrato de dados.
Neste artigo.
Este tópico lista as práticas recomendadas para criar contratos de dados que podem evoluir com facilidade ao longo do tempo. Para obter mais informações sobre contratos de dados, consulte os tópicos em Usando contratos de dados.
Nota sobre a validação do esquema.
Ao discutir o versionamento de contrato de dados, é importante observar que o esquema de contrato de dados exportado pelo Windows Communication Foundation (WCF) não possui nenhum suporte de versão, além do fato de que os elementos são marcados como opcionais por padrão.
Isso significa que mesmo o cenário de versão mais comum, como a inclusão de um novo membro de dados, não pode ser implementado de maneira uniforme em relação a um determinado esquema. As versões mais recentes de um contrato de dados (com um novo membro de dados, por exemplo) não valida usando o esquema antigo.
No entanto, há muitos cenários nos quais a conformidade estrita do esquema não é necessária. Muitas plataformas de serviços da Web, incluindo serviços Web WCF e XML criados usando ASP, não executam a validação de esquema por padrão e, portanto, toleram elementos extras que não são descritos pelo esquema. Ao trabalhar com essas plataformas, muitos cenários de versionamento são mais fáceis de implementar.
Assim, existem dois conjuntos de diretrizes de versão de contrato de dados: um conjunto para cenários em que a validade estrita do esquema é importante e outro definido para cenários quando não é.
Versionamento quando a validação de esquema é necessária.
Se a validade estrita do esquema for necessária em todas as direções (do novo para o antigo e do antigo para o novo), os contratos de dados devem ser considerados imutáveis. Se o controle de versão for necessário, um novo contrato de dados deverá ser criado, com um nome ou espaço de nomes diferente, e o contrato de serviço usando o tipo de dados deverá ser versionado de acordo.
Por exemplo, um contrato de serviço de processamento de pedido de compra denominado PoProcessing com uma operação PostPurchaseOrder usa um parâmetro em conformidade com um contrato de dados PurchaseOrder. Se o contrato PurchaseOrder tiver que ser alterado, você deverá criar um novo contrato de dados, ou seja, PurchaseOrder2, que inclui as alterações. Você deve, então, manipular o controle de versão no nível do contrato de serviço. Por exemplo, criando uma operação PostPurchaseOrder2 que usa o parâmetro PurchaseOrder2 ou criando um contrato de serviço PoProcessing2 no qual a operação PostPurchaseOrder adquire um contrato de dados PurchaseOrder2.
Observe que as alterações nos contratos de dados referenciados por outros contratos de dados também se estendem à camada do modelo de serviço. Por exemplo, no cenário anterior, o contrato de dados PurchaseOrder não precisa ser alterado. No entanto, ele contém um membro de dados de um contrato de dados do cliente, que por sua vez continha um membro de dados do contrato de dados do endereço, que precisa ser alterado. Nesse caso, você precisaria criar um contrato de dados Address2 com as alterações necessárias, um contrato de dados Customer2 que contém o membro de dados Address2 e um contrato de dados PurchaseOrder2 que contém um membro de dados Customer2. Como no caso anterior, o contrato de serviço teria que ser versionado também.
Embora nesses exemplos os nomes sejam alterados (anexando um "2"), a recomendação é alterar os namespaces em vez dos nomes, acrescentando novos namespaces com um número de versão ou uma data. Por exemplo, o contrato de dados schemas. contoso / 2005/05/21 / PurchaseOrder mudaria para o contrato de dados schemas. contoso / 2005/10/14 / PurchaseOrder.
Para obter mais informações, consulte Práticas recomendadas: versão de serviço.
Ocasionalmente, você deve garantir a conformidade estrita do esquema para mensagens enviadas por seu aplicativo, mas não pode confiar nas mensagens recebidas para serem estritamente compatíveis com o esquema. Nesse caso, há o perigo de que uma mensagem recebida possa conter dados irrelevantes. Os valores estranhos são armazenados e retornados pelo WCF e, portanto, resultam em mensagens inválidas de esquema sendo enviadas. Para evitar esse problema, o recurso round-tripping deve ser desativado. Existem duas maneiras de fazer isso.
Não implemente a interface IExtensibleDataObject em nenhum dos seus tipos.
Aplique um atributo ServiceBehaviorAttribute ao seu contrato de serviço com a propriedade IgnoreExtensionDataObject definida como true.
Para obter mais informações sobre viagens de ida e volta, consulte Contratos de dados compatíveis com o prazo.
Versionamento quando a validação de esquema não é necessária.
A conformidade estrita do esquema raramente é necessária. Muitas plataformas toleram elementos extras não descritos por um esquema. Desde que isso seja tolerado, o conjunto completo de recursos descritos em Controle de versão de contrato de dados e Contratos de dados compatíveis com encaminhamento pode ser usado. As diretrizes a seguir são recomendadas.
Algumas das diretrizes devem ser seguidas exatamente para enviar novas versões de um tipo onde um mais antigo é esperado ou enviar um antigo onde o novo é esperado. Outras diretrizes não são estritamente necessárias, mas estão listadas aqui porque podem ser afetadas pelo futuro do controle de versão do esquema.
Não tente contratar dados de versão por tipo de herança. Para criar versões posteriores, altere o contrato de dados em um tipo existente ou crie um novo tipo não relacionado.
O uso de herança junto com contratos de dados é permitido, desde que a herança não seja usada como um mecanismo de controle de versão e que determinadas regras sejam seguidas. Se um tipo deriva de um determinado tipo de base, não o faça derivar de um tipo base diferente em uma versão futura (a menos que tenha o mesmo contrato de dados). Há uma exceção: é possível inserir um tipo na hierarquia entre um tipo de contrato de dados e seu tipo base, mas somente se ele não contiver membros de dados com os mesmos nomes que outros membros em quaisquer versões possíveis dos outros tipos de dados. a hierarquia. Em geral, o uso de membros de dados com os mesmos nomes em níveis diferentes da mesma hierarquia de herança pode levar a sérios problemas de versão e deve ser evitado.
Começando com a primeira versão de um contrato de dados, sempre implemente o IExtensibleDataObject para habilitar o round-trip. Para obter mais informações, consulte Contratos de dados compatíveis com o encaminhamento. Se você liberou uma ou mais versões de um tipo sem implementar essa interface, implemente-a na próxima versão do tipo.
Em versões posteriores, não altere o nome do contrato de dados ou o namespace. Se estiver alterando o nome ou o namespace do tipo subjacente ao contrato de dados, certifique-se de preservar o nome do contrato de dados e o namespace usando os mecanismos apropriados, como a propriedade Name do DataContractAttribute. Para obter mais informações sobre nomenclatura, consulte Nomes de contrato de dados.
Em versões posteriores, não altere os nomes de nenhum membro de dados. Se estiver alterando o nome do campo, propriedade ou evento subjacente ao membro de dados, use a propriedade Name do DataMemberAttribute para preservar o nome do membro de dados existente.
Em versões posteriores, não altere o tipo de qualquer campo, propriedade ou evento subjacente a um membro de dados, de forma que o contrato de dados resultante para esse membro de dados seja alterado. Tenha em mente que os tipos de interface são equivalentes a Object para determinar o contrato de dados esperado.
Em versões posteriores, não altere a ordem dos membros de dados existentes ajustando a propriedade Order do atributo DataMemberAttribute.
Em versões posteriores, novos membros de dados podem ser adicionados. Eles devem sempre seguir estas regras:
A propriedade IsRequired deve sempre ser deixada com o valor padrão false.
Se um valor padrão de nulo ou zero para o membro for inaceitável, um método de retorno de chamada deverá ser fornecido usando o OnDeserializingAttribute para fornecer um padrão razoável, caso o membro não esteja presente no fluxo de entrada. Para obter mais informações sobre o retorno de chamada, consulte Chamadas de retorno de serialização tolerantes a versão.
A propriedade Order no DataMemberAttribute deve ser usada para garantir que todos os membros de dados adicionados recentemente apareçam após os membros de dados existentes. A maneira recomendada de fazer isso é a seguinte: Nenhum dos membros de dados na primeira versão do contrato de dados deve ter sua propriedade Order configurada. Todos os membros de dados adicionados na versão 2 do contrato de dados devem ter sua propriedade Order configurada como 2. Todos os membros de dados adicionados na versão 3 do contrato de dados devem ter seu Pedido configurado como 3 e assim por diante. É permitido ter mais de um membro de dados definido para o mesmo número de pedido.
Não remova membros de dados em versões posteriores, mesmo que a propriedade IsRequired tenha sido deixada em sua propriedade padrão de false nas versões anteriores.
Não altere a propriedade IsRequired em nenhum membro de dados existente de versão para versão.
Para membros de dados necessários (onde IsRequired é true), não altere a propriedade EmitDefaultValue de versão para versão.
Não tente criar hierarquias de versão ramificadas. Ou seja, sempre deve haver um caminho em pelo menos uma direção, de qualquer versão para qualquer outra versão, usando apenas as alterações permitidas por essas diretrizes.
Por exemplo, se a versão 1 de um contrato de dados Pessoa contiver apenas o membro de dados Nome, você não deverá criar a versão 2a do contrato, adicionando apenas o membro Age e a versão 2b, adicionando apenas o membro Address. Ir de 2a para 2b envolveria remover Idade e adicionar Endereço; indo na outra direção implicaria a remoção do endereço e adição de idade. A remoção de membros não é permitida por essas diretrizes.
Geralmente, você não deve criar novos subtipos de tipos de contratos de dados existentes em uma nova versão de seu aplicativo. Da mesma forma, você não deve criar novos contratos de dados que sejam usados ​​no lugar de membros de dados declarados como Objeto ou como tipos de interface. A criação dessas novas classes é permitida apenas quando você sabe que pode adicionar os novos tipos à lista de tipos conhecidos de todas as instâncias do aplicativo antigo. Por exemplo, na versão 1 do seu aplicativo, você pode ter o tipo de contrato de dados LibraryItem com os subtipos de contrato de dados Book e Newspaper. LibraryItem teria, então, uma lista de tipos conhecidos que contém Book e Newspaper. Suponha que você agora adicione um tipo de revista na versão 2, que é um subtipo de LibraryItem. Se você enviar uma instância de revista da versão 2 para a versão 1, o contrato de dados de revista não é encontrado na lista de tipos conhecidos e uma exceção é lançada.
Você não deve adicionar ou remover membros de enumeração entre versões. Você também não deve renomear membros de enumeração, a menos que você use a propriedade Name no atributo EnumMemberAttribute para manter seus nomes no modelo de contrato de dados da mesma forma.
Coleções são intercambiáveis ​​no modelo de contrato de dados, conforme descrito em Tipos de coleta em contratos de dados. Isso permite um grande grau de flexibilidade. No entanto, certifique-se de não alterar inadvertidamente um tipo de coleção de maneira não intercambiável de versão para versão. Por exemplo, não mude de uma coleção não personalizada (isto é, sem o atributo CollectionDataContractAttribute) para uma customizada ou uma customizada para uma não customizada. Além disso, não altere as propriedades no CollectionDataContractAttribute de versão para versão. A única alteração permitida é adicionar uma propriedade Name ou Namespace se o nome ou espaço de nomes do tipo de coleta subjacente tiver sido alterado e você precisar tornar o nome do contrato de dados e o namespace iguais aos de uma versão anterior.
Algumas das diretrizes listadas aqui podem ser ignoradas com segurança quando circunstâncias especiais se aplicam. Certifique-se de entender completamente os mecanismos de serialização, desserialização e esquema envolvidos antes de se desviar das diretrizes.

Estratégias de versionamento.
Artigos desta série.
Depois que os serviços são enviados para a produção, seus documentos WSDL associados - que representam terminais de serviços, protocolos e contratos relacionados que descrevem operações e mensagens - não devem ser alterados. Ou, no mínimo, as alterações devem ser compatíveis com versões anteriores para que os clientes existentes não sejam afetados quando as alterações forem publicadas. Nesta seção, discutirei como os contratos do WCF suportam compatibilidade com versões anteriores e explico algumas estratégias de versão que você pode considerar para os aplicativos do WCF.
Contratos do WCF e compatibilidade com versões anteriores.
Os contratos do WCF são tolerantes à versão por padrão. A Figura 1 e a Figura 2 resumem mudanças típicas em contratos de serviço e contratos de dados e descrevem o impacto para os clientes existentes. Em suma, o DataContractSerializer permite a falta de dados desnecessários e ignora dados supérfluos para contratos de serviço, contratos de dados e, da mesma forma, contratos de mensagens. Apenas a remoção de operações ou a adição ou remoção de dados necessários causam problemas em clientes existentes.
Figura 1: Contratos de serviço e compatibilidade com versões anteriores
Adicionando novos parâmetros a uma assinatura de operação.
Cliente não afetado. Novos parâmetros inicializados para valores padrão no serviço.
Removendo parâmetros de uma assinatura de operação.
Cliente não afetado. Parâmetros supérfluos transmitidos por clientes são ignorados, dados perdidos no serviço.
Modificando os tipos de parâmetros.
Uma exceção ocorrerá se o tipo de entrada do cliente não puder ser convertido para o tipo de dados do parâmetro.
Modificando os tipos de valor de retorno.
Uma exceção ocorrerá se o valor de retorno do serviço não puder ser convertido para o tipo de dados esperado na versão do cliente da assinatura da operação.
Adicionando novas operações.
Cliente não afetado. Não invocará operações das quais não saiba nada.
Uma exceção ocorrerá. As mensagens enviadas pelo cliente para o serviço são consideradas como usando um cabeçalho de ação desconhecido.
Figura 2: Contratos de dados e compatibilidade com versões anteriores
Adicione novos membros não obrigatórios.
Cliente não afetado. Valores ausentes são inicializados para os padrões.
Adicione novos membros obrigatórios.
Uma exceção é lançada para valores ausentes.
Remova membros não obrigatórios.
Dados perdidos no serviço. Não é possível devolver o conjunto de dados completo ao cliente, por exemplo. Sem exceções.
Remova os membros necessários.
Uma exceção é lançada quando o cliente recebe respostas do serviço com valores ausentes.
Modifique os tipos de dados de membros existentes.
Se os tipos forem compatíveis, não haverá exceção, mas poderão receber resultados inesperados.
Escolhendo uma estratégia de versionamento.
A tolerância à versão é boa, pois oferece aos desenvolvedores uma maneira flexível de lidar com mudanças. Como o DataContractSerializer é tolerante à versão, teoricamente você pode evitar a versão oficial de contratos e terminais que expõem esses contratos até que uma alteração significativa seja introduzida, como remover operações de um contrato de serviço ou adicionar ou remover membros necessários de um contrato de dados.
Há também possíveis efeitos colaterais da tolerância de versão:
Se você adicionar novas operações a um contrato de serviço, apenas os clientes que referenciarem o WSDL mais recente saberão sobre essas operações e você não poderá controlar quais dos seus clientes existentes atualizaram seu WSDL, a menos que exponha um novo endpoint quando forem feitas alterações. Se você adicionar membros de dados não obrigatórios a um contrato de dados, talvez seja necessário escrever um código extra para inicializar valores ausentes para algo significativo - em vez de usar o valor padrão. Se você remover membros de dados não obrigatórios de um contrato de dados, poderá haver problemas de ida e volta em que os dados transmitidos aos serviços ou devolvidos aos clientes serão perdidos. Pode ser difícil rastrear problemas se você não acompanhar as diferentes versões dos contratos, pois as alterações são feitas na produção.
É importante escolher uma estratégia de versão apropriada que atenda às necessidades, às vezes conflitantes, de agilidade e produtividade versus controle de alterações. Aqui estão algumas estratégias de versão a serem consideradas:
Versão Agile: Confie na compatibilidade com versões anteriores o máximo de tempo possível e evite o contrato formal e a versão do endpoint até que a compatibilidade seja interrompida. Essa abordagem é útil em ambientes ágeis que exigem atualizações freqüentes do código de produção. Versão Estrita: Execute o contrato formal e a versão de endpoint para qualquer alteração em um contrato de serviço, contrato de dados, contrato de mensagem ou outras alterações relacionadas ao contrato ou ao terminal. Essa abordagem é melhor em ambientes com atualizações de produção menos frequentes ou que exigem rastreamento detalhado de todas e quaisquer alterações. Versão semestrada: execute contrato formal e versão de endpoint quando contratos ou endpoints são modificados de forma que sua diretiva exija o rastreamento da alteração. Por exemplo, sua política pode ser permitir que novas operações sejam adicionadas a um contrato de serviço, mas se forem feitas alterações nas operações existentes ou se qualquer contrato de dados for alterado de forma que sejam semanticamente diferentes, ele exige o controle de versão. Essa abordagem está em algum lugar entre versões ágeis e estritas.
A abordagem ágil de controle de versão - mostrada na Figura 3 - significa fazer alterações nos contratos de dados e contratos de serviço existentes sem fazer a versão deles ou fornecer novos pontos de extremidade. Versão restrita significa fornecer novos contratos de dados, contratos de serviço e terminais, como mostrado na Figura 4.
Figura 3: Versão Agile através do mesmo contrato de serviço e endpoint.
Figura 4: Controle estrito de versão através de um novo contrato de serviço e endpoint exclusivo.
É melhor decidir sobre uma política de controle de versão antes de liberar a primeira versão para produção.
Contratos de serviço de controle de versão.
Para formalizar a versão de um contrato de serviço, você deve fazer o seguinte:
Faça uma cópia do contrato original com um novo nome de tipo de interface, o mesmo nome de contrato e um novo namespace. Faça as modificações necessárias na definição do contrato. Implemente o novo contrato de serviço no mesmo tipo de serviço, se possível. Você pode usar a implementação explícita do contrato para canalizar solicitações para as diferentes implementações de método, se necessário. Adicione um novo endpoint para o novo contrato de serviço ao existente & lt; service & gt; configuração. Como alternativa, você pode usar uma classe básica comum que implemente operações de serviços principais e forneça substituições no tipo derivado de cada versão. Essa pode ser uma abordagem melhor se houver alterações significativas na implementação do serviço ou se os comportamentos de segurança do serviço forem diferentes do serviço original. Isso exigirá um procedimento & lt; service & gt; separado entrada no arquivo de configuração.
A Figura 5 mostra um exemplo de controle rigoroso de contrato de serviço com uma implementação de serviço compartilhado. Observe que a propriedade Name do ServiceContractAttribute é a mesma para as duas versões do contrato, enquanto o nome do tipo de interface muda de IServiceA para IServiceA2. Observe também que dois terminais de serviço estão configurados - um para cada contrato.
Figura 5: Versão 1 e 2 de ServiceAContract com configuração de terminal relacionada.

Uma estratégia de controle de versão.
A Web Service Software Factory agora é mantida pela comunidade e pode ser encontrada no site da Service Factory.
Este conteúdo está desatualizado e não está mais sendo mantido. É fornecido como uma cortesia para indivíduos que ainda estão usando essas tecnologias.
Esta página pode conter URLs que eram válidos quando publicados originalmente, mas agora vinculam a sites ou páginas que não existem mais.
Aposentado: novembro de 2011.
Tarefas específicas devem ser executadas durante o desenvolvimento do serviço para reduzir a complexidade da evolução do serviço. Essas tarefas e decisões de design são definidas nas seções a seguir e serão aumentadas com cenários em uma versão futura deste tópico.
Os namespaces XML qualificam elementos e atributos XML em um documento para impedir que sejam interpretados como nós diferentes com o mesmo nome local. Namespaces distintos podem ser aplicados a várias partes de um serviço da Web, mas na maioria dos casos, apenas dois tipos de namespaces precisam ser definidos: um para a interface de serviço e outro para os tipos reutilizáveis ​​definidos nas mensagens.
O espaço de nomes definido para o serviço pode ser usado em todas as partes do serviço (por exemplo, ligações, mensagens ou interfaces), porque essas partes geralmente não são implantadas e versionadas independentemente umas das outras.
As mensagens são compostas de tipos primitivos (por exemplo, strings e inteiros) e / ou tipos personalizados. Os tipos personalizados podem ser usados ​​apenas para uma única operação ou podem ter sido definidos como parte de um esquema empresarial ou de uma especificação do setor para serem reutilizados em operações ou serviços. Como os tipos reutilizáveis ​​são usados ​​com outros serviços, eles devem ter um namespace diferente da interface de serviço.
Um identificador que representa a versão principal da interface e os tipos reutilizáveis ​​devem ser refletidos no namespace. O mês e ano da data de lançamento é comumente usado para esse identificador (por exemplo, globalbank / PaymentServices / PaymentTransferService / 2006/12).
As mensagens referem-se à carga útil de dados e metadados transferidos entre um serviço e o consumidor. Uma mensagem pode ser uma solicitação ou resposta e contém tipos primitivos e complexos. Para mais informações sobre mensagens, consulte Design de Mensagens.
As mensagens são um elemento comum de serviços que evoluem com o tempo. Como elas são projetadas influenciam a facilidade com que elas evoluem e como são úteis em outros contextos. O objetivo do design da mensagem, no que se refere à versão, é ser o mais explícito possível para a descrição do serviço, sem perder a capacidade de aplicar pequenas revisões no futuro.
Essas metas podem ser alcançadas tornando todas as propriedades opcionais para as mensagens e os tipos complexos que as mensagens contêm. Para apreciar esse design, é útil compará-lo com outros designs de mensagens usados:
Strings e XML. Algumas mensagens são definidas como uma única cadeia de caracteres e essa cadeia pode ou não conter dados XML. Outras mensagens têm um tipo que é um nó ou elemento XML. Ambos os designs compartilham vantagens e desvantagens comuns. Eles são muito fáceis de evoluir porque não há expectativas sobre as mensagens, mas, como eles não definem nenhuma expectativa, são inúteis de uma perspectiva de geração de código. Como resultado disso, se uma API amigável ao desenvolvedor for desejada para o consumidor ou serviço, muito mais trabalho é necessário. Digitação forte. Algumas mensagens definem explicitamente cada propriedade e especificam se esse valor é obrigatório. Esse design resulta em uma API robusta para o serviço e seus consumidores, mas reduz a flexibilidade de como as mensagens evoluem.
Existem outras vantagens para esse design de mensagem. Os membros de mensagens e tipos personalizados são opcionais por padrão no ASMX e no WCF. O mecanismo de serialização usado pelos serviços ASMX e WCF também manipula membros opcionais corretamente.
A validação de mensagens é um requisito comum para muitos serviços. O documento WSDL ou esquemas XML relacionados sendo usados ​​para definir mensagens não devem ser usados ​​para realizar essa validação por razões definidas anteriormente em Princípios e Motivações. Em vez disso, a validação deve usar documentos externos. Esses documentos podem ser esquemas XML, instruções de expressões regulares ou algum outro documento. As regras de validação e os meios para aplicá-las devem ser definidas na documentação do serviço.
Desacoplar os requisitos de validação da descrição de serviço também permite que cada um desses itens evolua de forma independente. Mudanças nos requisitos de validação podem resultar em uma quebra ou mudança ininterrupta. O mesmo é verdade sobre uma alteração na descrição do serviço.
As seguintes tarefas devem ser concluídas ao desenvolver um serviço:
Revisões secundárias: não altere o namespace XML da mensagem, tipo ou serviço que está sendo alterado. Não altere o endereço do terminal do serviço. Novos consumidores deste serviço podem ser implantados, mas os consumidores existentes continuarão a operar como antes da mudança. Publique nova documentação, metadados e notificações sobre a alteração de acordo com o processo de controle de alterações que foi comunicado. Principais revisões: Altere o namespace XML para refletir a nova data de lançamento. Implante o novo serviço em um ambiente de teste para que os consumidores possam ser testados. Altere o endereço do terminal do serviço. Teste e implante os novos consumidores do serviço. Descontinuar o serviço antigo de uma maneira e em um cronograma de acordo com a política de controle de alterações que foi comunicada.
Freqüentemente, as restrições são colocadas em um serviço por alguns de seus consumidores. Essas restrições reduzem a flexibilidade que o serviço precisa evoluir. Nesse cenário, o serviço pode optar por evoluir de maneira diferente para diferentes consumidores. Para que isso aconteça, o consumidor deve enviar alguma forma de informação que distingue o consumidor na mensagem. A interface de serviço usa essas informações para despachar a mensagem para a implementação apropriada.
Outra opção para aumentar a flexibilidade envolve associar um consumidor às operações específicas que o consumidor usará. Essa associação pode ocorrer durante a assinatura de um serviço e pode ser atualizada a qualquer momento. These associations will allow the service to know exactly what consumers will be affected by specific changes to the service.

Web Services Versioning.
by Gabriel Bechara.
Introdução.
Web services are bound to change and evolve over time. The loose coupling principles of service-oriented architecture (SOA) imply that service providers can release a new version of a shared service without waiting for consumers to adapt, and that service consumers should test and certify on a new shared service version before switching. Consequently, you might need to have multiple versions of a shared service running concurrently and simultaneously accessible by different service consumers. Some service consumers might need to continue using an old version of a service until migration of the consumer code occurs. Therefore, Web services versioning is an important subject that should be considered carefully in all enterprise SOA approaches.
Current standards for Web services have no explicit support for versioning, requiring architects and developers to solve the problem through the application of patterns. This article will:
Identify the types of changes that can occur in services.
By the end of this article, you should have a good understanding of the main aspects that should be dealt with when building your own enterprise Web services versioning strategy.
Types of Changes.
A change in a Web services implementation may affect its consumers depending on a number of factors:
A change in the operation parameters of a Web service. This might involve the addition of new parameters (this will affect the current consumers), or a change in existing parameters, such as a change in an XML document that might be used as a message parameter in a Web service. The changes in an XML document may involve the addition of optional elements or attributes (this might affect the current consumers) or of mandatory elements (this will affect the current consumers).
Therefore, a typology of change in Web services can be created in relation to the impact on the current consumers of those services. One approach is to qualify a change that will not affect the current consumers as a minor release and a change that will affect the current consumers as a major release.
Minor Release.
A minor release can be one of two types. The first is a correction of a bug or a performance enhancement. This type will not affect the Web Services Description Language (WSDL) of the Web service. The second type consists of adding new methods to a Web service, wherein the WSDL is changed with no impact on service consumers. A distinction can be made between these two types when labeling those versions. For example, for the first type you can change the second decimal place of the version number (1.0X), while for the second type you change the first decimal place of the version number (1.Y0).
Major Release.
A major release involves a change that will break backwards compatibility. In this case the consumers must be modified. A release that only affects the functionalities of a Web service, without affecting the WSDL, is also considered a major release. This is because the current consumers cannot invoke the new version without considering the Web service's modified functionalities. Now that we have identified the various types of changes and their impact on current consumers, let's take a look at different patterns for Web services versioning.
The Patterns.
Consumer Binding Pattern.
When a new version of a Web service is released -- whether a major or minor release -- the consumers are notified about the change, and are responsible for changing the code to access the new version. The new WSDL is published -- in a UDDI registry, for example -- and a notification is sent to the consumers so that they can find the new service and establish binding with the new service provider. One practice for using a UDDI registry involves associating a given version of a portType to a unique tModel. One WSDL is associated with one tModel. This tModel should contain a reference to the version number for a major release because two major versions will imply two different WSDLs. The tModel may contain a reference to the minor version if two minor versions need to be accessed at one time. A consumer of that portType/version could do a green-pages UDDI search for services that advertise compliance by associating themselves with the tModel of the corresponding version.
This method may impose changes in the consumers' code, at least in the search performed on the registry for accessing a version (major or minor) of a service, even for minor releases. And what if you need to have two minor versions running at the same time? For instance, you might want to deploy a new minor release on a test site to be used by a limited number of consumers, while maintaining the old version for the rest. The consumers of the service deployed on the test site will need to change the end point of the service even if the WSDL is not modified (because it's a minor version). In this specific case, it may be useful to have a layer of indirection between the consumers and the providers, to drive the migration of different consumers in a graceful way.
Figure 1. Consumer Binding Pattern.
Note: The consumer binding pattern does not imply the use of UDDI; it refers to the fact that the binding decision is made on the consumer side. We'll discuss interesting uses of this pattern in a moment.
Layer of Indirection Pattern.
When a new minor version of a Web service is released, the consumer can transparently migrate to the new release. This ability is provided by the layer of indirection through a routing mechanism that ensures content-based routing or user-based routing (based on the IP of the requester, for instance, or on the principal of the requester when propagating security roles) to call the different versions of a Web service.
The use of a layer of indirection allows two minor releases to coexist without changing the consumers' code, and helps to ensure a graceful migration to a new release.
Figure 2. Layer of Indirection Pattern.
But in the case of a major release, the consumers will need to change their code. And what if, for some organizational reason, we need to migrate to a new major release without changing the current consumers' code, calling the new service with the old client? This might happen if, for example, some regulatory reason implies a change accessible only through the use of the new major release of a service, provided by a business partner external to your organization. This leads to using an adapter to enable the use of a new major release for current consumers until all the consumers' code is modified.
Adapter Pattern.
The adapter pattern consists of adapting the client request and response to be able to consume a new major release of a service. Using this pattern offers a smoother migration, in case the use of a new major version of a service is mandatory for some business, regulatory, or organizational reason.
Figure 3. Adapter Pattern.
Solutions for Applying the Patterns.
The different patterns can be applied in different ways. This can be done in the consumers' code, but that is rarely the case because it can cause coding delays and increase the complexity of the code handling versioning. An alternative is to use a mediation layer for decoupling the consumer from the provider and to apply those patterns in the mediation layer. Using Oracle Service Bus as a mediation layer will provide the functionalities of the Layer of Indirection pattern associated with the Adapter Pattern, relieving the consumers' code from those concerns. Veja a Figura 4.
Figure 4. Applying the patterns using Oracle Service Bus.
Using this approach based on Oracle Service Bus offers these advantages:
A minor release change can be addressed without modifying the consumers, and test sites can be addressed through content-based or user-based routing.
Mediation in Oracle Service Bus is mainly configured using proxies to access business services. In between there are pipelines, consisting of stages, actions, branches, and routing nodes. The message is adapted within those pipelines, routing the requests in the routing nodes. The configuration of the proxies and the business services can be organized with a reference to the version numbers. The proxies in Oracle Service Bus may include in their path a reference to the major release, and the business service may include the major and minor release. For example, for a major v1.XX, we will have one proxy, one or more business services (one per minor release), and one WSDL:
. and for major V2.XX:
Note: Because the proxies and the WSDL are the same for minor releases, the path containing those does not need to include a reference to the minor version.
We have addressed the access to different services through Oracle Service Bus. But there are other issues to deal with, such as the deployment of two different versions of a service provider coming from the same development environment. Those services might have the same Java Platform, Enterprise Edition (Java EE) Web module context path, because they may have been developed using the same development tools. Therefore, unless you provide a build script that adds version reference in the context of the Java EE Web module, you might want to consider deploying different versions of the same service on different targets. (A target is a cluster or a managed server.) See Figure 5.
Figure 5. Deploying service providers on different Targets.
Note: Some frameworks and development tools, including Oracle JDeveloper, automate the versioning of some service providers. That capability has been extended in Oracle JDeveloper 11 Technical Preview 4 to deal with the versioning of Service Component Architecture (SCA) composites (multiple services in one composite).
Presentation services and orchestration services (business process services) will benefit from the transparency of this approach when consuming other services belonging to the business services layer or the data access services layer. But what about consumers of presentation services? A composite portal can consume presentation services using Web Services for Remote Portlets (WSRP) to consume remote portlets. The Layer of Indirection pattern, coupled with the Adapter Pattern using Oracle Service Bus, can also be applied in this case, but we may use a more adapted approach based on the portal capabilities. Portals usually come with administration tools for configuring access to portlets (reusable presentation services). Using users' role-based rules and entitlements to display some part of the composite portal, depending on the user properties, may be more appropriate for the presentation services. This is more of a concern with a composite portal engine than with Oracle Service Bus.
Therefore, presentation services layer versioning is better accommodated using the Consumer Binding pattern. In this context, the pattern is not applied by using a UDDI registry to choose the service. In this case, applying this pattern relies on the entitlements or personalization engine provided by the composite portal. An important aspect of this particular use of this pattern is that the choice of the version is made through configuration, in the portal administration tool. Thus, it will not imply any code modification or maintenance.
The figure below shows how a composite portal can consume portlets through WSRP in different versions of the same application. The selection of the portlet version to be exposed is made in the composite portal engine.
Figure 6. The Consumer Binding Pattern applied to presentation services.
Doing this allows two versions of the same application to run simultaneously, exposing new functionalities only to selected end users based on user profile attributes.
Conclusão.
Web services versioning can be handled in a variety of ways, depending on business constraints and the layer to which the service belongs. In this article we've covered practices that can be applied to a variety of versioning tasks:
Accessing and deploying multiple versions of a service provider at the same time.
Some additional factors should be taken into consideration, including XML Schemas versioning and managing dependencies between services and the XML Schemas used by those services. At the organizational level, this will become very difficult to handle without the proper tools for managing dependencies and for driving the changes properly and holistically.
Gabriel Bechara has worked with Oracle-BEA presales and consulting services since 2003. A 15-year veteran of the software industry, Gabriel has served as an architect and advisor on large projects, providing practical experience and feedback on concepts that can provide a foundation for building new information systems. His interests include methodologies for defining software and enterprise architectures, with a strong focus on business integration and SOA.

No comments:

Post a Comment