Zona .Net

Refatorando idéias, produzindo conhecimento.

Posts Tagged ‘Versionamento de Servico

Versionamento de Serviços WCF

leave a comment »

Uma das cosias que devemos ter em mente é que nossos aplicativos sempre irão sofrer alterações, seja por necessidade de evolução ou correção de bugs. Ter em mãos ferramentas que permitam que essas mudanças não sejam traumáticas é sempre bom e a gente só percebe a importância quando precisa.

Quando construímos um serviço WCF normalmente criamos um contrato fazendo uso de interfaces e a implementação desse contrato em uma classe. Além disso, devemos definir um Binding e um endereço do serviço, e tudo isso pode mudar. Caso eu tenha que adicionar ou remover uma nova operação (método), tenho que alterar o contrato. Posso querer alterar também o endereço onde o serviço será exposto, ou incluir um novo binding para contemplar interoperabilidade e por fim, posso mudar a implementação para refletir uma mudança de regra.

Algumas mudanças não afetam a forma como as mensagens são processadas, mantendo assim a compatibilidade com a versão anterior. Esse tipo de alteração é chamada de “nonbreaking change”, e as alterações que afetam o processamento da mensagem é chamada de “breaking change”.

O ideal é que todas as alterações sejam “nonbreaking change”, pois elas seriam transparentes para os consumidores do serviço. Lembrando que o contrato usado no server não precisa ser o mesmo usado no client, basta que sejam compatíveis em semântica. Então por padrão (ASP.NET Web Service e WCF) qualquer adição de operações no serviço não causará quebra de compatibilidade, já se houver remoção ou alteração de assinatura ou nome haverá quebra, esse comportamente é chamado de “Lax Versioning”, ou seja, não há validação de Schema. Vale ressaltar que nem toda plataforma ou tecnologia suporta Lax Versioning.

Caso haja necessidade de alterar um tipo que é passado entre uma chamada de uma operação, normalmente decorado com o atributo DataContract podemos tomar a decisão baseados no que queremos que os clientes vejam. Caso seja desejável que todos os cliente vejam o novo tipo alterado, devemos criar uma nova versão do DataContract, ServiceContract (em um namespace diferente) e um novo EndPoint, ou seja, o cliente terá que apontar para a nova versão do serviço. Se a modificação puder ser visualizada apenas para os novos clientes, é uma boa prática, embora não obrigatório que os DataContracts implementem a interface IExtensibleDataObject. Implementando essa interface embora os clientes antigos não vejam os novos membros, eles são passados entre as chamadas e não perdem seu valor, ou seja, são sempre serializados.

Vejamos alguns exemplos de alterações Nonbreaking.

Versao 01

<DataContract>
Public Class Cliente
	<DataMember>
	Dim Nome as String
End Class

Versao 02

<DataContract>
Public Class Cliente
	<DataMember(Name :=”Nome”)>
	Dim NomeCompleto as String
End Class

No caso acima o alteramos o nome do membro, mas não houve quebra, pois o DataContract não foi alterado, já que ele leva em consideração o parâmetro Name do atributo DataMember.

Agora vejamos um exemplo de inclusão de novo membro no DataContract.

Versao 01

<DataContract Name :=”Cliente”>
Public Class ClienteV1
	<DataMember>
	Dim Nome as String
End Class

Versao 02

<DataContract Name :=”Cliente”>
Public Class ClienteV2
	<DataMember>
	Dim Nome As String
  	<DataMember>
 	Dim CPF As String
End Class

Na versao 02 foi incluído um novo membro, mas a propriedade Name do atributo DataContract estão iguais, sendo assim são o mesmo contrato. Caso o cliente ainda esteja com a versão 01, ele pode receber o dado gerado no servidor usando a versão 02 (que serializará os dois membros), mas na deserialização ele não encontrara o membro CPF, logo irá ignorá-lo. Ao enviar o dado de volta para o servidor ele serializará apenas os membros que ele conhece, ou seja, apenas o membro Nome. Então quando ocorrer a deserialização no servidor será visto o membro enviado, ou seja, o servidor não verá mais o membro CPF que foi enviado, atribuindo assim o valor default. Com isso perdemos dados entre as chamadas, embora não haja quebra de compatibilidade entre os contratos.

Para evitar essa perda de informação entre as chamadas de versões diferentes usamos a interface citada anteriormente (IExtensibleDataObject). Isso deve ser feito logo na primeira versão, pois se implementada posteriormente as versões anteriores irão quebrar.

Versao 01

<DataContract>
Public Class Cliente
	Implements IExtensibleDataObject

	<DataMember>
	Dim Nome As String

    Public Overridable Property ExtensionData As ExtensionDataObject Implements _
	IExtensibleDataObject.ExtensionData
		Get
			Return oData
		End Get
		Set
			oData = Value
 		End Set
 	End Property
End Class

Versao 02

<DataContract>
Public Class Cliente
	Implements IExtensibleDataObject

	<DataMember>
	Dim Nome As String
	<DataMember>
	Dim CPF As String

    Public Overridable Property ExtensionData As ExtensionDataObject Implements _
	IExtensibleDataObject.ExtensionData
		Get
			Return oData
		End Get
		Set
			oData = Value
 		End Set
 	End Property
End Class

Dessa forma quando a infra-estrutura WCF encontra um dado que não faz parte do contrato original, ele armazena seu valor nessa propriedade. Quando o dado chega novamente ao remetente, que conhece a nova versão, ele extrairá o valor armazenado nessa propriedade e fará a deserialização sem perda de informação. Caso haja possibilidade de evolução do DataContract implemente essa interface desde a primeira versão, pois a implementação posterior gerará uma Breaking change.

Algumas alterações são sempre “Breaking changing” tais como trocar o Name ou Namespace do DataContract/ServiceContract, trocar a ordem dos membros do DataContract usando a propriedade Order do Atributo DataMember, renomear um DataMember/OperationContract, remover um DataMember/OperationContract, ou qualquer outra alteração de assinatura dos membros.

Apresentei apenas algumas idéias iniciais de como o WCF é robusto e flexível nessa questão de versionamento, para mais informações veja os links utilizados como referência.

Referências:
http://msdn.microsoft.com/en-us/library/ms733832.aspx
http://msdn.microsoft.com/en-us/library/ms731060.aspx
http://msdn.microsoft.com/en-us/library/ms731138.aspx
http://msdn.microsoft.com/en-us/library/ms733112.aspx
http://msdn.microsoft.com/en-us/library/ms731083.aspx


MVP Logo Leonardo Bruno Lima
Microsoft MVP | MCT | MCTS | MCPD
Attps Informática [http://www.attps.com.br]
+55 (85) 99449511
GMail: lblima.net@gmail.com
Live Mail: lblima_net@hotmail.com
   
Blogs: http://lblima.blogspot.com | https://zonadotnet.wordpress.com

“I do not agree with what you have to say, but I’ll defend to the death your
right to say it.” Voltaire.

Anúncios

Written by Leonardo Bruno Lima

25 de agosto de 2009 at 2:25 am

Publicado em Uncategorized

Tagged with ,