Usando contratos de dados
Um contrato de dados é um contrato formal entre um serviço e um cliente que descreve abstratamente os dados a serem trocados. Ou seja, para se comunicar, o cliente e o serviço não precisam compartilhar os mesmos tipos, apenas os mesmos contratos de dados. Um contrato de dados define precisamente, para cada parâmetro ou tipo de retorno, quais dados são serializados (transformados em XML) a serem trocados.
Noções básicas do contrato de dados
O WCF (Windows Communication Foundation) usa um mecanismo de serialização chamado Serializador de Contrato de Dados por padrão para serializar e desserializar dados (convertê-los de e para XML). Todos os tipos primitivos do .NET Framework, como inteiros e cadeias de caracteres, bem como determinados tipos tratados como primitivos, como DateTime e XmlElement, podem ser serializados sem nenhuma outra preparação e são considerados como tendo contratos de dados padrão. Muitos tipos de .NET Framework também têm contratos de dados existentes. Para obter uma lista completa de tipos serializáveis, consulte Tipos compatíveis com o Serializador de Contrato de Dados.
Novos tipos complexos que você cria precisam ter um contrato de dados definido para que sejam serializáveis. Por padrão, o DataContractSerializer infere o contrato de dados e serializa todos os tipos publicamente visíveis. Todas as propriedades públicas de leitura/gravação e campos do tipo são serializadas. Você pode recusar membros da serialização usando o IgnoreDataMemberAttribute. Você também pode criar explicitamente um contrato de dados usando atributos DataContractAttribute e DataMemberAttribute. Normalmente, isso é feito aplicando o atributo DataContractAttribute ao tipo. Esse atributo pode ser aplicado a classes, estruturas e enumerações. O atributo DataMemberAttribute precisa ser aplicado a cada membro do tipo de contrato de dados para indicar que ele é um membro de dados, ou seja, ele deve ser serializado. Para obter mais informações, consulte Tipos serializáveis.
Exemplo
O exemplo a seguir mostra um contrato de serviço (uma interface) ao qual os atributos ServiceContractAttribute e OperationContractAttribute foram aplicados explicitamente. O exemplo mostra que os tipos primitivos não exigem um contrato de dados, enquanto um tipo complexo exige.
[ServiceContract]
public interface ISampleInterface
{
// No data contract is required since both the parameter
// and return types are primitive types.
[OperationContract]
double SquareRoot(int root);
// No Data Contract required because both parameter and return
// types are marked with the SerializableAttribute attribute.
[OperationContract]
System.Drawing.Bitmap GetPicture(System.Uri pictureUri);
// The MyTypes.PurchaseOrder is a complex type, and thus
// requires a data contract.
[OperationContract]
bool ApprovePurchaseOrder(MyTypes.PurchaseOrder po);
}
<ServiceContract()> _
Public Interface ISampleInterface
' No data contract is required since both the parameter and return
' types are both primitive types.
<OperationContract()> _
Function SquareRoot(ByVal root As Integer) As Double
' No Data Contract required because both parameter and return
' types are marked with the SerializableAttribute attribute.
<OperationContract()> _
Function GetPicture(ByVal pictureUri As System.Uri) As System.Drawing.Bitmap
' The MyTypes.PurchaseOrder is a complex type, and thus
' requires a data contract.
<OperationContract()> _
Function ApprovePurchaseOrder(ByVal po As MyTypes.PurchaseOrder) As Boolean
End Interface
O exemplo a seguir mostra como um contrato de dados para o tipo MyTypes.PurchaseOrder
é criado aplicando os atributos DataContractAttribute e DataMemberAttribute à classe e aos seus membros.
namespace MyTypes
{
[DataContract]
public class PurchaseOrder
{
private int poId_value;
// Apply the DataMemberAttribute to the property.
[DataMember]
public int PurchaseOrderId
{
get { return poId_value; }
set { poId_value = value; }
}
}
}
Namespace MyTypes
<System.Runtime.Serialization.DataContractAttribute()> _
Public Class PurchaseOrder
Private poId_value As Integer
' Apply the DataMemberAttribute to the property.
<DataMember()> _
Public Property PurchaseOrderId() As Integer
Get
Return poId_value
End Get
Set
poId_value = value
End Set
End Property
End Class
End Namespace
Observações
As anotações a seguir fornecem itens a serem considerados ao criar contratos de dados:
O atributo IgnoreDataMemberAttribute só é honrado quando usado com tipos não marcados. Isso inclui tipos que não são marcados com um dos atributos DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute ou EnumMemberAttribute marcados como serializáveis por qualquer outro meio (como IXmlSerializable).
Você pode aplicar o atributo DataMemberAttribute a campos e propriedades.
Os níveis de acessibilidade do membro (interno, privado, protegido ou público) não afetam o contrato de dados de forma alguma.
O atributo DataMemberAttribute será ignorado se for aplicado a membros estáticos.
Durante a serialização, o código de obtenção de propriedade é chamado para que os membros de dados de propriedade obtenham o valor das propriedades a serem serializadas.
Durante a desserialização, um objeto não inicializado é criado pela primeira vez, sem chamar construtores no tipo. Em seguida, todos os membros de dados são desserializados.
Durante a desserialização, o código do conjunto de propriedades é chamado para que os membros de dados de propriedade definam as propriedades como o valor sendo desserializado.
Para que um contrato de dados seja válido, a serialização de todos os seus membros de dados precisa ser possível. Para obter uma lista completa de tipos serializáveis, consulte Tipos compatíveis com o Serializador de Contrato de Dados.
Tipos genéricos são tratados exatamente da mesma forma que tipos não genéricos. Não há requisitos especiais para parâmetros genéricos. Por exemplo, considere o seguinte XML.
[DataContract]
public class MyGenericType1<T>
{
// Code not shown.
}
<DataContract()> _
Public Class MyGenericType1(Of T)
' Code not shown.
End Class
Esse tipo é serializável se o tipo usado para o parâmetro de tipo genérico (T
) é serializável ou não. Como precisa ser possível serializar todos os membros de dados, o tipo a seguir só será serializável se o parâmetro de tipo genérico também for serializável, conforme mostrado no código a seguir.
[DataContract]
public class MyGenericType2<T>
{
[DataMember]
T theData;
}
<DataContract()> _
Public Class MyGenericType2(Of T)
<DataMember()> _
Dim theData As T
End Class
Para obter um exemplo de código completo de um serviço WCF que define um contrato de dados, consulte o exemplo de Contrato de Dados Básico.
Confira também
- DataMemberAttribute
- DataContractAttribute
- Tipos serializáveis
- Nomes de contrato de dados
- Equivalência de contrato de dados
- Ordem de membro de dados
- Tipos de contratos de dados conhecidos
- Contratos de dados compatíveis por encaminhamento
- Controle de versão de contrato de dados
- Retornos de chamada de serialização tolerantes à versão
- Valores padrões de membro de dados
- Tipos com suporte fornecido pelo serializador de contrato de dados
- Como: criar um contrato de dados básicos para uma classe ou estrutura