Ferramenta Contract-First
Muitas vezes, contratos de serviço precisam ser criados usando serviços existentes. No .NET Framework 4.5 e posteriores, as classes de contrato de dados podem ser criadas automaticamente com base em serviços existentes usando a ferramenta contract-first. Para usar a ferramenta contract-first, o arquivo de definição de esquema XML (XSD) deve ser baixado localmente; a ferramenta não pode importar contratos de dados remotos por HTTP.
A ferramenta contract-first é integrada ao Visual Studio 2012 como uma tarefa de build. Os arquivos de código gerados pela tarefa de build são criados sempre que o projeto é compilado, de modo que o projeto possa adotar facilmente as alterações no contrato de serviço subjacente.
Os tipos de esquema que a ferramenta contract-first pode importar incluem os seguintes:
<xsd:complexType>
<xsd:simpleType>
</xsd:simpleType>
</xsd:complexType>
Tipos simples não serão gerados se forem primitivos como Int16
ou String
; tipos complexos não serão gerados se forem do tipo Collection
. Os tipos também não serão gerados se fizerem parte de outro xsd:complexType
. Em todos esses casos, os tipos serão referenciados a tipos existentes no projeto.
Adicionando um contrato de dados a um projeto
Antes que a ferramenta contract-first possa ser usada, o XSD (contrato de serviço) precisa ser adicionado ao projeto. Para fins desta visão geral, o contrato a seguir será usado para ilustrar as funções de contract-first. Essa definição de serviço é um pequeno subconjunto do contrato de serviço usado pela API de pesquisa do Bing.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="ServiceSchema"
targetNamespace="http://tempuri.org/ServiceSchema.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/ServiceSchema.xsd"
xmlns:mstns="http://tempuri.org/ServiceSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:complexType name="SearchRequest">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Version" type="xs:string" default="2.2" />
<xs:element minOccurs="0" maxOccurs="1" name="Market" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="UILanguage" type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="Query" type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="AppId" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="Latitude" type="xs:double" />
<xs:element minOccurs="0" maxOccurs="1" name="Longitude" type="xs:double" />
<xs:element minOccurs="0" maxOccurs="1" name="Radius" type="xs:double" />
</xs:sequence>
</xs:complexType>
<xs:simpleType name="WebSearchOption">
<xs:restriction base="xs:string">
<xs:enumeration value="DisableHostCollapsing" />
<xs:enumeration value="DisableQueryAlterations" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Para adicionar o contrato de serviço acima ao projeto, clique com o botão direito do mouse no projeto e selecione Adicionar Novo.... Selecione Definição de Esquema no painel do WCF da caixa de diálogo Modelos e dê ao novo arquivo o nome SampleContract.xsd. Copie e cole o código acima na exibição de código do novo arquivo.
Configurando opções de contract-first
As opções de contract-first podem ser configuradas no menu Propriedades de um projeto do WCF. Para habilitar o desenvolvimento de contract-first, marque a caixa de seleção Habilitar XSD como Linguagem de Definição de Tipo na página do WCF da janela de propriedades do projeto.
Para configurar propriedades avançadas, clique no botão Avançado.
As configurações avançadas a seguir podem ser definidas para a geração de código baseada em contratos. As configurações só podem ser definidas para todos os arquivos no projeto; não é possível defini-las para arquivos individuais no momento.
Modo de Serializador: essa configuração determina qual serializador é usado para ler arquivos de contrato de serviço. Quando o Serializador XML é selecionado, as opções Tipos de Coleção e Tipos de Reutilização ficam desabilitadas. Essas opções se aplicam somente ao Serializador de Contrato de Dados.
Tipos de Reutilização: essa configuração especifica quais bibliotecas são usadas para reutilização de tipo. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
Tipo de Coleção: essa configuração especifica o tipo totalmente qualificado ou qualificado para assembly a ser usado para o tipo de dados de coleção. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
Tipo de Dicionário: essa configuração especifica o tipo totalmente qualificado ou qualificado para assembly a ser usado para o tipo de dados de dicionário.
EnableDataBinding: essa configuração especifica se a interface INotifyPropertyChanged deve ser implementada em todos os tipos de dados para implementar a associação de dados.
ExcludedTypes: essa configuração especifica a lista de tipos totalmente qualificados ou qualificados para assembly a serem excluídos dos assemblies referenciados. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
GenerateInternalTypes: essa configuração especifica se devem ser geradas classes marcadas como internas. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
GenerateSerializableTypes: essa configuração especifica se devem ser geradas classes com o atributo SerializableAttribute. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
ImportXMLTypes: essa configuração especifica se o serializador de contrato de dados deve ser configurado para aplicar o atributo SerializableAttribute a classes sem o atributo DataContractAttribute. Ela só se aplicará se o Modo de Serializador estiver definido como Serializador de Contrato de Dados.
SupportFx35TypedDataSets: essa configuração especifica se deve ser fornecida funcionalidade adicional para conjuntos de dados tipados criados para o .NET Framework 3.5. Quando o Modo de Serializador for definido como Serializador XML, a extensão TypedDataSetSchemaImporterExtensionFx35 será adicionada ao importador do esquema XML quando esse valor for definido como True. Quando o Modo de Serializador for definido como Serializador de Contrato de Dados, o tipo DateTimeOffset será excluído das Referências quando esse valor for definido como False, de modo que um DateTimeOffset sempre seja gerado para versões mais antigas da estrutura.
InputXsdFiles: essa configuração especifica a lista de arquivos de entrada. Cada arquivo deve conter um esquema XML válido.
Idioma: essa configuração especifica o idioma do código de contrato gerado. A configuração deve ser reconhecida por CodeDomProvider.
NamespaceMappings: essa configuração especifica os mapeamentos dos Namespaces de Destino XSD para os namespaces CLR. Cada mapeamento deve usar o seguinte formato:
"Schema Namespace, CLR Namespace"
O Serializador XML aceita apenas um mapeamento no seguinte formato:
"*, CLR Namespace"
OutputDirectory: essa configuração especifica o diretório em que os arquivos de código serão gerados.
As configurações serão usadas para gerar tipos de contrato de serviço dos arquivos de contrato de serviço quando o projeto for criado.
Usando o desenvolvimento contract-first
Depois de adicionar o contrato de serviço ao projeto e confirmar as configurações de build, compile o projeto pressionando F6. Os tipos definidos no contrato de serviço estarão disponíveis para uso no projeto.
Para usar os tipos definidos no contrato de serviço, adicione uma referência ao ContractTypes
no namespace atual:
using MyProjectNamespace.ContractTypes;
Os tipos definidos no contrato de serviço serão resolvidos no projeto, conforme mostrado abaixo:
Os tipos gerados pela ferramenta são criados no arquivo GeneratedXSDTypes.cs. O arquivo é criado no diretório <diretório do projeto>/obj/<configuração de build>/XSDGeneratedCode/ por padrão. O esquema de exemplo no início deste artigo é convertido da seguinte maneira:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17330
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestXSD3.ContractTypes
{
using System.Xml.Serialization;
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17330")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/ServiceSchema.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/ServiceSchema.xsd", IsNullable=true)]
public partial class SearchRequest
{
private string versionField;
private string marketField;
private string uILanguageField;
private string queryField;
private string appIdField;
private double latitudeField;
private bool latitudeFieldSpecified;
private double longitudeField;
private bool longitudeFieldSpecified;
private double radiusField;
private bool radiusFieldSpecified;
public SearchRequest()
{
this.versionField = "2.2";
}
/// <remarks/>
[System.ComponentModel.DefaultValueAttribute("2.2")]
public string Version
{
get
{
return this.versionField;
}
set
{
this.versionField = value;
}
}
/// <remarks/>
public string Market
{
get
{
return this.marketField;
}
set
{
this.marketField = value;
}
}
/// <remarks/>
public string UILanguage
{
get
{
return this.uILanguageField;
}
set
{
this.uILanguageField = value;
}
}
/// <remarks/>
public string Query
{
get
{
return this.queryField;
}
set
{
this.queryField = value;
}
}
/// <remarks/>
public string AppId
{
get
{
return this.appIdField;
}
set
{
this.appIdField = value;
}
}
/// <remarks/>
public double Latitude
{
get
{
return this.latitudeField;
}
set
{
this.latitudeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool LatitudeSpecified
{
get
{
return this.latitudeFieldSpecified;
}
set
{
this.latitudeFieldSpecified = value;
}
}
/// <remarks/>
public double Longitude
{
get
{
return this.longitudeField;
}
set
{
this.longitudeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool LongitudeSpecified
{
get
{
return this.longitudeFieldSpecified;
}
set
{
this.longitudeFieldSpecified = value;
}
}
/// <remarks/>
public double Radius
{
get
{
return this.radiusField;
}
set
{
this.radiusField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool RadiusSpecified
{
get
{
return this.radiusFieldSpecified;
}
set
{
this.radiusFieldSpecified = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17330")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/ServiceSchema.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/ServiceSchema.xsd", IsNullable=false)]
public enum WebSearchOption
{
/// <remarks/>
DisableHostCollapsing,
/// <remarks/>
DisableQueryAlterations,
}
}
Erros e avisos
Erros e avisos encontrados na análise do esquema XSD aparecerão como erros de build e avisos.
Herança de interface
Não é possível usar a herança de interface com o desenvolvimento contract-first; isso é consistente com a maneira como as interfaces se comportam em outras operações. Para usar uma interface que herda uma interface base, use dois pontos de extremidade separados. O primeiro ponto de extremidade usa o contrato herdado e o segundo implementa a interface base.