Comparando os Serviços Web do ASP.NET com o WCF com base no processo de desenvolvimento

O Windows Communication Foundation (WCF) tem uma opção de modo de compatibilidade ASP.NET para permitir que aplicativos WCF sejam programados e configurados como ASP.NET serviços Web e imitem seu comportamento. As seções a seguir comparam ASP.NET serviços Web e WCF com base no que é necessário para desenvolver aplicativos usando ambas as tecnologias.

Representação de dados

O desenvolvimento de um serviço Web com ASP.NET geralmente começa com a definição de tipos de dados complexos que o serviço deve usar. ASP.NET depende do XmlSerializer para traduzir dados representados por tipos do .NET Framework para XML para transmissão a ou de um serviço, e para traduzir dados recebidos como XML em objetos do .NET Framework. Definir os tipos de dados complexos que um serviço de ASP.NET deve usar requer a definição de classes do .NET Framework que o XmlSerializer possa serializar de e para XML. Essas classes podem ser gravadas manualmente ou geradas a partir de definições dos tipos no Esquema XML usando o Utilitário de Suporte a Esquemas XML/Tipos de Dados de linha de comando, xsd.exe.

Veja a seguir uma lista dos principais problemas a serem considerados na definição de classes do .NET Framework que o XmlSerializer pode serializar de e para XML:

  • Somente os campos públicos e as propriedades dos objetos do .NET Framework são convertidos em XML.

  • Instâncias de classes de coleção só poderão ser serializadas em XML se as classes implementarem a interface IEnumerable ou ICollection.

  • Classes que implementam a IDictionary interface, como Hashtable, não podem ser serializadas em XML.

  • Os grandes tipos de atributo no System.Xml.Serialization namespace podem ser adicionados a uma classe .NET Framework e seus membros para controlar como as instâncias da classe são representadas no XML.

O desenvolvimento de aplicativos WCF geralmente também começa com a definição de tipos complexos. O WCF pode usar os mesmos tipos do .NET Framework que os serviços Web ASP.NET.

O WCFDataContractAttribute e DataMemberAttribute pode ser adicionado aos tipos do .NET Framework para indicar que as instâncias do tipo devem ser serializadas em XML e quais campos ou propriedades específicos do tipo devem ser serializados, conforme mostrado no código de exemplo a seguir.

//Example One:
[DataContract]
public class LineItem
{
    [DataMember]
    public string ItemNumber;
    [DataMember]
    public decimal Quantity;
    [DataMember]
    public decimal UnitPrice;
}

//Example Two:
public class LineItem
{
    [DataMember]
    private string itemNumber;
    [DataMember]
    private decimal quantity;
    [DataMember]
    private decimal unitPrice;

    public string ItemNumber
    {
      get
      {
          return this.itemNumber;
      }

      set
      {
          this.itemNumber = value;
      }
    }

    public decimal Quantity
    {
        get
        {
            return this.quantity;
        }

        set
        {
            this.quantity = value;
        }
    }

    public decimal UnitPrice
    {
      get
      {
          return this.unitPrice;
      }

      set
      {
          this.unitPrice = value;
      }
    }
}

//Example Three:
public class LineItem
{
     private string itemNumber;
     private decimal quantity;
     private decimal unitPrice;

     [DataMember]
     public string ItemNumber
     {
       get
       {
          return this.itemNumber;
       }

       set
       {
           this.itemNumber = value;
       }
     }

     [DataMember]
     public decimal Quantity
     {
          get
          {
              return this.quantity;
          }

          set
          {
             this.quantity = value;
          }
     }

     [DataMember]
     public decimal UnitPrice
     {
          get
          {
              return this.unitPrice;
          }

          set
          {
              this.unitPrice = value;
          }
     }
}

Significa DataContractAttribute que zero ou mais campos ou propriedades de um tipo devem ser serializados, enquanto indica DataMemberAttribute que um determinado campo ou propriedade deve ser serializado. Pode DataContractAttribute ser aplicado a uma classe ou estrutura. Pode DataMemberAttribute ser aplicado a um campo ou a uma propriedade, e os campos e propriedades aos quais o atributo é aplicado podem ser públicos ou privados. Instâncias de tipos que têm o DataContractAttribute aplicado a eles são conhecidas como contratos de dados no WCF. Eles são serializados em XML usando DataContractSerializer.

Veja a seguir uma lista das diferenças importantes entre o uso do DataContractSerializer e o uso do XmlSerializer e dos atributos do namespace System.Xml.Serialization.

  • Os XmlSerializer atributos e os System.Xml.Serialization atributos do namespace são projetados para permitir que você mapeie tipos do .NET Framework para qualquer tipo válido definido no Esquema XML e, portanto, eles fornecem um controle muito preciso sobre como um tipo é representado em XML. O DataContractSerializer, DataContractAttribute e DataMemberAttribute fornecer muito pouco controle sobre como um tipo é representado em XML. Você só pode especificar os namespaces e nomes usados para representar o tipo e seus campos ou propriedades no XML e a sequência na qual os campos e propriedades aparecem no XML:

    [DataContract(
    Namespace="urn:Contoso:2006:January:29",
    Name="LineItem")]
    public class LineItem
    {
          [DataMember(Name="ItemNumber",IsRequired=true,Order=0)]
          public string itemNumber;
          [DataMember(Name="Quantity",IsRequired=false,Order = 1)]
          public decimal quantity;
          [DataMember(Name="Price",IsRequired=false,Order = 2)]
          public decimal unitPrice;
    }
    

    Todo o resto sobre a estrutura do XML usado para representar o tipo .NET é determinado pelo DataContractSerializer.

  • Ao não permitir muito controle sobre como um tipo deve ser representado no XML, o processo de serialização torna-se altamente previsível para DataContractSerializer, e, portanto, mais fácil de otimizar. Um benefício prático do design do DataContractSerializer é o melhor desempenho, uma melhora de aproximadamente 10% no desempenho.

  • Os atributos para uso com o XmlSerializer não indicam quais campos ou propriedades do tipo são serializados em XML, enquanto o DataMemberAttribute para uso com os DataContractSerializer mostra explicitamente quais campos ou propriedades são serializados. Portanto, os contratos de dados são contratos explícitos sobre a estrutura dos dados que um aplicativo deve enviar e receber.

  • XmlSerializer só pode converter os membros públicos de um objeto .NET em XML, enquanto DataContractSerializer pode converter os membros dos objetos em XML, independentemente dos modificadores de acesso desses membros.

  • Como consequência de ser capaz de serializar os membros não públicos de tipos em XML, o DataContractSerializer enfrenta menos restrições sobre a variedade de tipos .NET que pode serializar em XML. Em particular, ele pode ser traduzido em tipos XML como Hashtable que implementam a interface IDictionary. É muito mais provável que DataContractSerializer consiga serializar as instâncias de qualquer tipo .NET pré-existente em XML, sem precisar modificar a definição do tipo ou desenvolver um invólucro para ele.

  • Outra consequência de DataContractSerializer ser capaz de acessar os membros não públicos de um tipo é que isso requer confiança total, enquanto XmlSerializer não requer. A permissão de acesso de código de Confiança Total fornece acesso completo a todos os recursos em um computador que podem ser acessados usando as credenciais sob as quais o código está sendo executado. Essa opção deve ser usada com cuidado, pois o código totalmente confiável acessa todos os recursos em seu computador.

  • O DataContractSerializer incorpora algum suporte para controle de versão:

    • O DataMemberAttribute tem uma propriedade IsRequired que pode receber um valor false para membros adicionados às novas versões de um contrato de dados que não estavam presentes nas versões anteriores, permitindo assim que aplicativos com a versão mais recente do contrato possam processar versões anteriores.

    • Ao fazer com que um contrato de dados implemente a IExtensibleDataObject interface, é possível permitir que o DataContractSerializer passe os membros definidos em versões mais recentes de um contrato de dados através de aplicativos com versões anteriores do contrato.

Apesar de todas as diferenças, o XML para o qual o XmlSerializer serializa um tipo por padrão é semanticamente idêntico ao XML para o qual o DataContractSerializer serializa um tipo, desde que o namespace para o XML seja definido explicitamente. A classe a seguir, que tem atributos para uso com ambos os serializadores, é traduzida em XML semanticamente idêntico pelo XmlSerializerDataContractAttribute:

[Serializable]
[XmlRoot(Namespace="urn:Contoso:2006:January:29")]
[DataContract(Namespace="urn:Contoso:2006:January:29")]
public class LineItem
{
     [DataMember]
     public string ItemNumber;
     [DataMember]
     public decimal Quantity;
     [DataMember]
     public decimal UnitPrice;
}

O SDK (kit de desenvolvimento de software) do Windows inclui uma ferramenta de linha de comando chamada ServiceModel Metadata Utility Tool (Svcutil.exe). Assim como a ferramenta xsd.exe usada com ASP.NET serviços Web, Svcutil.exe pode gerar definições de tipos de dados .NET do Esquema XML. Os tipos serão contratos de dados se o DataContractSerializer puder emitir o XML no formato definido pelo Esquema XML; caso contrário, eles serão destinados à serialização por meio do XmlSerializer. Svcutil.exe também pode gerar um esquema XML a partir de contratos de dados usando sua dataContractOnly opção.

Observação

Embora os serviços Web do ASP.NET usem o XmlSerializer, e o modo de compatibilidade ASP.NET do WCF faça com que os serviços WCF imitem o comportamento dos serviços Web do ASP.NET, a opção de compatibilidade ASP.NET não restringe ao uso do XmlSerializer. Ainda é possível usar o DataContractSerializer com serviços que estão em execução no modo de compatibilidade ASP.NET.

Desenvolvimento de serviços

Para desenvolver um serviço usando ASP.NET, é costume adicionar o WebService atributo a uma classe e o WebMethodAttribute a qualquer um dos métodos dessa classe que sejam operações do serviço.

[WebService]
public class Service : T:System.Web.Services.WebService
{
    [WebMethod]
    public string Echo(string input)
    {
       return input;
    }
}

ASP.NET 2.0 introduziu a opção de adicionar os atributos WebService e WebMethodAttribute a uma interface em vez de a uma classe e escrever uma classe para implementar a interface:

[WebService]
public interface IEcho
{
    [WebMethod]
    string Echo(string input);
}

public class Service : IEcho
{

   public string Echo(string input)
   {
        return input;
    }
}

Usar essa opção é preferencial, pois a interface com o WebService atributo constitui um contrato para as operações executadas pelo serviço que podem ser reutilizados com várias classes que podem implementar esse mesmo contrato de maneiras diferentes.

Um serviço WCF é fornecido ao definir um ou mais endpoints WCF. Um ponto de extremidade é definido por um endereço, um vínculo e um contrato de serviço. O endereço define onde o serviço está localizado. A associação especifica como se comunicar com o serviço. O contrato de serviço define as operações que o serviço pode executar.

O contrato de serviço geralmente é definido primeiro, adicionando ServiceContractAttribute e OperationContractAttribute a uma interface:

[ServiceContract]
public interface IEcho
{
     [OperationContract]
     string Echo(string input);
}

Especifica ServiceContractAttribute que a interface define um contrato de serviço WCF e OperationContractAttribute indica quais, se houver, dos métodos da interface definem operações do contrato de serviço.

Depois que um contrato de serviço é definido, ele é implementado em uma classe, fazendo com que a classe implemente a interface pela qual o contrato de serviço é definido:

public class Service : IEcho
{
    public string Echo(string input)
    {
       return input;
    }
}

Uma classe que implementa um contrato de serviço é conhecida como um tipo de serviço no WCF.

A próxima etapa é associar um endereço e uma associação a um tipo de serviço. Normalmente, isso é feito em um arquivo de configuração, editando o arquivo diretamente ou usando um editor de configuração fornecido com o WCF. Aqui está um exemplo de um arquivo de configuração.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
     <system.serviceModel>
      <services>
      <service name="Service ">
       <endpoint
        address="EchoService"
        binding="basicHttpBinding"
        contract="IEchoService "/>
      </service>
      </services>
     </system.serviceModel>
</configuration>

A associação especifica o conjunto de protocolos para se comunicar com o aplicativo. A tabela a seguir lista as associações fornecidas pelo sistema que representam opções comuns.

Nome Propósito
BasicHttpBinding Interoperabilidade com serviços Web e clientes que dão suporte ao WS-BasicProfile 1.1 e ao Perfil de Segurança Básica 1.0.
WSHttpBinding Interoperabilidade com serviços Web e clientes que dão suporte aos protocolos WS-* via HTTP.
WSDualHttpBinding Comunicação HTTP duplex, pela qual o receptor de uma mensagem inicial não responde diretamente ao remetente inicial, mas pode transmitir qualquer número de respostas durante um período de tempo usando HTTP em conformidade com protocolos WS-*.
WSFederationBinding Comunicação HTTP, na qual o acesso aos recursos de um serviço pode ser controlado com base nas credenciais emitidas por um provedor de credenciais explicitamente identificado.
NetTcpBinding Comunicação segura, confiável e de alto desempenho entre entidades de software do WCF em uma rede.
NetNamedPipeBinding Comunicação segura, confiável e de alto desempenho entre entidades de software WCF no mesmo computador.
NetMsmqBinding Comunicação entre entidades de software do WCF usando o MSMQ.
MsmqIntegrationBinding Comunicação entre uma entidade de software do WCF e outra entidade de software usando o MSMQ.
NetPeerTcpBinding Comunicação entre entidades de software do WCF usando a Rede Ponto a Ponto do Windows.

A associação BasicHttpBinding fornecida pelo sistema incorpora o conjunto de protocolos suportados pelos serviços Web do ASP.NET.

As associações personalizadas para aplicativos WCF são facilmente definidas como coleções das classes de elemento de associação que o WCF usa para implementar protocolos individuais. Novos elementos de associação podem ser gravados para representar protocolos adicionais.

O comportamento interno dos tipos de serviço pode ser ajustado usando as propriedades de uma família de classes chamadas comportamentos. Aqui, a ServiceBehaviorAttribute classe é usada para especificar que o tipo de serviço deve ser multithreaded.

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class DerivativesCalculatorServiceType: IDerivativesCalculator

Alguns comportamentos, como ServiceBehaviorAttribute, são atributos. Outros, os que tiverem propriedades que os administradores gostariam de definir, podem ser modificados na configuração de um aplicativo.

Em tipos de serviço de programação, o uso frequente é feito da OperationContext classe. Sua propriedade estática Current fornece acesso a informações sobre o contexto em que uma operação está em execução. OperationContext é semelhante às classes HttpContext e ContextUtil.

Hosting

Os serviços Web ASP.NET são compilados em um assembly de biblioteca de classes. Um arquivo chamado arquivo de serviço é fornecido que tem a extensão .asmx e contém uma @ WebService diretiva que identifica a classe que contém o código para o serviço e o assembly no qual ele está localizado.

<%@ WebService Language="C#" Class="Service,ServiceAssembly" %>

O arquivo de serviço é copiado para o diretório raiz do aplicativo ASP.NET no IIS (Serviços de Informações da Internet), e o assembly é copiado para o subdiretório \bin desse diretório raiz do aplicativo. Em seguida, o aplicativo é acessível usando a URL (uniform resource locator) do arquivo de serviço na raiz do aplicativo.

Os serviços do WCF podem ser hospedados prontamente no IIS 5.1 ou 6.0, no WAS (Serviço de Ativação de Processo do Windows) fornecido como parte do IIS 7.0 e em qualquer aplicativo .NET. Para hospedar um serviço no IIS 5.1 ou 6.0, o serviço deve usar HTTP como o protocolo de transporte de comunicações.

Para hospedar um serviço no IIS 5.1, 6.0 ou no WAS, use as seguintes etapas:

  1. Compile o tipo de serviço em um assembly de biblioteca de classes.

  2. Crie um arquivo de serviço com uma extensão .svc com uma @ ServiceHost diretiva para identificar o tipo de serviço:

    <%@ServiceHost language="c#" Service="MyService" %>

  3. Copie o arquivo de serviço em um diretório virtual e o assembly para o subdiretório \bin desse diretório virtual.

  4. Copie o arquivo de configuração para o diretório virtual e nomeie-o Web.config.

Em seguida, o aplicativo é acessível usando a URL do arquivo de serviço na raiz do aplicativo.

Para hospedar um serviço WCF em um aplicativo .NET, compile o tipo de serviço em um assembly de biblioteca de classes referenciado pelo aplicativo e programe o aplicativo para hospedar o serviço usando a ServiceHost classe. Veja a seguir um exemplo da programação básica necessária:

string httpBaseAddress = "http://www.contoso.com:8000/";
string tcpBaseAddress = "net.tcp://www.contoso.com:8080/";

Uri httpBaseAddressUri = new Uri(httpBaseAddress);
Uri tcpBaseAddressUri = new Uri(tcpBaseAddress);

Uri[] baseAddresses = new Uri[] {
 httpBaseAddressUri,
 tcpBaseAddressUri};

using(ServiceHost host = new ServiceHost(
typeof(Service), //"Service" is the name of the service type baseAddresses))
{
     host.Open();

     […] //Wait to receive messages
     host.Close();
}

Este exemplo mostra como os endereços de um ou mais protocolos de transporte são especificados na construção de um ServiceHost. Esses endereços são chamados de endereços base.

O endereço fornecido para qualquer ponto de extremidade de um serviço WCF é um endereço relativo a um endereço base do host do ponto de extremidade. O host pode ter um endereço base para cada protocolo de transporte de comunicação. Na configuração de exemplo no arquivo de configuração anterior, o BasicHttpBinding selecionado para o ponto de extremidade usa HTTP como o protocolo de transporte, portanto, EchoServiceo endereço do ponto de extremidade é relativo ao endereço base HTTP do host. No caso do host no exemplo anterior, o endereço base HTTP é http://www.contoso.com:8000/. Para um serviço hospedado no IIS ou WAS, o endereço base é a URL do arquivo de serviço do serviço.

Somente os serviços hospedados no IIS ou WAS, configurados exclusivamente com HTTP como protocolo de transporte, podem utilizar a opção de modo de compatibilidade do WCF ASP.NET. Ativar essa opção requer as etapas a seguir.

  1. O programador deve adicionar o AspNetCompatibilityRequirementsAttribute atributo ao tipo de serviço e especificar que ASP.NET modo de compatibilidade é permitido ou necessário.

    [System.ServiceModel.Activation.AspNetCompatibilityRequirements(
          RequirementsMode=AspNetCompatibilityRequirementsMode.Require)]
    public class DerivativesCalculatorServiceType: IDerivativesCalculator
    
  2. O administrador deve configurar o aplicativo para usar o modo de compatibilidade ASP.NET.

    <configuration>
         <system.serviceModel>
          <services>
          […]
          </services>
          <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        </system.serviceModel>
    </configuration>
    

    Os aplicativos WCF também podem ser configurados para usar .asmx como a extensão para seus arquivos de serviço em vez de .svc.

    <system.web>
         <compilation>
          <compilation debug="true">
          <buildProviders>
           <remove extension=".asmx"/>
           <add extension=".asmx"
            type="System.ServiceModel.ServiceBuildProvider,
            System.ServiceModel,
            Version=3.0.0.0,
            Culture=neutral,
            PublicKeyToken=b77a5c561934e089" />
          </buildProviders>
          </compilation>
         </compilation>
    </system.web>
    

    Essa opção pode salvá-lo de ter que modificar clientes configurados para usar as URLs de arquivos de serviço .asmx ao modificar um serviço para usar o WCF.

Desenvolvimento do cliente

Clientes para ASP.NET serviços Web são gerados usando a ferramenta de linha de comando, WSDL.exe, que fornece a URL do arquivo .asmx como entrada. A ferramenta correspondente fornecida pelo WCF é a ServiceModel Metadata Utility Tool (Svcutil.exe). Ele gera um módulo de código com a definição do contrato de serviço e a definição de uma classe de cliente WCF. Ele também gera um arquivo de configuração com o endereço e a associação do serviço.

Na programação de um cliente de um serviço remoto, geralmente é aconselhável programar de acordo com um padrão assíncrono. O código gerado pela ferramenta WSDL.exe sempre fornece um padrão síncrono e assíncrono. O código gerado pela ServiceModel Metadata Utility Tool (Svcutil.exe) pode suportar qualquer um dos padrões. Ele oferece o padrão síncrono como opção padrão. Se a ferramenta for executada com a opção /async , o código gerado fornecerá o padrão assíncrono.

Não há garantia de que os nomes nas classes de cliente do WCF geradas pela ferramenta de WSDL.exe do ASP.NET, por padrão, correspondam aos nomes nas classes de cliente do WCF geradas pela ferramenta Svcutil.exe. Em particular, os nomes das propriedades das classes que precisam ser serializadas usando o XmlSerializer têm, por padrão, o sufixo Property no código gerado pela ferramenta Svcutil.exe, o que não ocorre com a ferramenta WSDL.exe.

Representação da mensagem

Os cabeçalhos das mensagens SOAP enviadas e recebidas por ASP.NET serviços Web podem ser personalizados. Uma classe é derivada de SoapHeader para definir a estrutura do cabeçalho e, em seguida, a SoapHeaderAttribute é usada para indicar a presença do cabeçalho.

public class SomeProtocol : SoapHeader
{
     public long CurrentValue;
     public long Total;
}

[WebService]
public interface IEcho
{
     SomeProtocol ProtocolHeader
     {
      get;
     set;
     }

     [WebMethod]
     [SoapHeader("ProtocolHeader")]
     string PlaceOrders(PurchaseOrderType order);
}

public class Service: WebService, IEcho
{
     private SomeProtocol protocolHeader;

     public SomeProtocol ProtocolHeader
     {
         get
         {
              return this.protocolHeader;
         }

         set
         {
              this.protocolHeader = value;
         }
     }

     string PlaceOrders(PurchaseOrderType order)
     {
         long currentValue = this.protocolHeader.CurrentValue;
     }
}

O WCF fornece os atributos MessageContractAttribute, MessageHeaderAttribute e MessageBodyMemberAttribute para descrever a estrutura das mensagens SOAP enviadas e recebidas por um serviço.

[DataContract]
public class SomeProtocol
{
     [DataMember]
     public long CurrentValue;
     [DataMember]
     public long Total;
}

[DataContract]
public class Item
{
     [DataMember]
     public string ItemNumber;
     [DataMember]
     public decimal Quantity;
     [DataMember]
     public decimal UnitPrice;
}

[MessageContract]
public class ItemMessage
{
     [MessageHeader]
     public SomeProtocol ProtocolHeader;
     [MessageBody]
     public Item Content;
}

[ServiceContract]
public interface IItemService
{
     [OperationContract]
     public void DeliverItem(ItemMessage itemMessage);
}

Essa sintaxe produz uma representação explícita da estrutura das mensagens, enquanto a estrutura de mensagens está implícita pelo código de um serviço Web ASP.NET. Além disso, na sintaxe ASP.NET, os cabeçalhos de mensagem são representados como propriedades do serviço, como a ProtocolHeader propriedade no exemplo anterior, enquanto na sintaxe WCF, eles são representados com mais precisão como propriedades de mensagens. Além disso, o WCF permite que os cabeçalhos das mensagens sejam adicionados à configuração dos pontos de extremidade.

<service name="Service ">
     <endpoint
      address="EchoService"
      binding="basicHttpBinding"
      contract="IEchoService ">
      <headers>
      <dsig:X509Certificate
       xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
       ...
      </dsig:X509Certificate>
      </headers>
     </endpoint>
</service>

Essa opção permite evitar qualquer referência a cabeçalhos de protocolo infraestrutural no código de um cliente ou serviço: os cabeçalhos são adicionados às mensagens devido à forma como o ponto de extremidade é configurado.

Descrição do serviço

A emissão de uma solicitação HTTP GET para o arquivo .asmx de um serviço Web ASP.NET com a consulta WSDL faz com que ASP.NET gerem WSDL para descrever o serviço. Ele retorna esse WSDL como a resposta à solicitação.

ASP.NET 2.0 possibilitou validar se um serviço está em conformidade com o Perfil Básico 1.1 da Organização de Services-Interoperability Web (WS-I) e inserir uma declaração de que o serviço está em conformidade com seu WSDL. Isso é feito usando os parâmetros ConformsTo e EmitConformanceClaims do atributo WebServiceBindingAttribute.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(
     ConformsTo = WsiProfiles.BasicProfile1_1,
     EmitConformanceClaims=true)]
public interface IEcho

O WSDL que ASP.NET gera para um serviço pode ser personalizado. As personalizações são feitas criando uma classe derivada de ServiceDescriptionFormatExtension adicionar itens ao WSDL.

A emissão de uma solicitação HTTP GET com a consulta WSDL do arquivo .svc de um serviço WCF com um ponto de extremidade HTTP hospedado no IIS 51, 6.0 ou WAS faz com que o WCF responda ao WSDL para descrever o serviço. A emissão de uma solicitação HTTP GET com a consulta WSDL para o endereço base HTTP de um serviço hospedado em um aplicativo .NET terá o mesmo efeito se httpGetEnabled for definido como true.

No entanto, o }WCF também responde às solicitações WS-MetadataExchange com o WSDL gerado por ele para descrever um serviço. ASP.NET serviços Web não têm suporte interno para solicitações WS-MetadataExchange.

O WSDL gerado pelo WCF pode ser amplamente personalizado. A classe ServiceMetadataBehavior oferece alguns recursos para personalização do WSDL. O WCF também pode ser configurado para não gerar WSDL, mas sim para usar um arquivo WSDL estático em uma determinada URL.

<behaviors>
     <behavior name="DescriptionBehavior">
     <metadataPublishing
      enableMetadataExchange="true"
      enableGetWsdl="true"
      enableHelpPage="true"
      metadataLocation=
      "http://localhost/DerivativesCalculatorService/Service.WSDL"/>
     </behavior>
</behaviors>

Tratamento de exceção

Em ASP.NET serviços Web, exceções sem tratamento são retornadas aos clientes como falhas SOAP. Você também pode lançar explicitamente instâncias da SoapException classe e ter mais controle sobre o conteúdo da falha SOAP que é transmitida para o cliente.

Nos serviços do WCF, exceções sem tratamento não são retornadas aos clientes como falhas SOAP para evitar que informações confidenciais sejam expostas inadvertidamente por meio das exceções. Uma configuração é fornecida para ter exceções sem tratamento retornadas aos clientes para fins de depuração.

Para retornar falhas SOAP aos clientes, você pode lançar instâncias do tipo genérico, FaultException<TDetail>, usando o tipo de contrato de dados como tipo genérico. Você também pode adicionar FaultContractAttribute atributos às operações para especificar as falhas que uma operação pode produzir.

[DataContract]
public class MathFault
{
     [DataMember]
     public string operation;
     [DataMember]
     public string problemType;
}

[ServiceContract]
public interface ICalculator
{
     [OperationContract]
     [FaultContract(typeof(MathFault))]
     int Divide(int n1, int n2);
}

Isso fará com que as falhas possíveis sejam anunciadas no WSDL do serviço, permitindo que os programadores de cliente antevejam quais falhas podem resultar de uma operação e gravem as instruções catch apropriadas.

try
{
     result = client.Divide(value1, value2);
}
catch (FaultException<MathFault> e)
{
 Console.WriteLine("FaultException<MathFault>: Math fault while doing "
  + e.Detail.operation
  + ". Problem: "
  + e.Detail.problemType);
}

Gerenciamento de estado

A classe usada para implementar um serviço Web ASP.NET pode ser derivada de WebService.

public class Service : WebService, IEcho
{

 public string Echo(string input)
 {
  return input;
 }
}

Nesse caso, a classe pode ser programada para usar a propriedade Context da WebService classe base para acessar um HttpContext objeto. O HttpContext objeto pode ser usado para atualizar e recuperar informações de estado do aplicativo usando sua propriedade Application e pode ser usado para atualizar e recuperar informações de estado de sessão usando sua propriedade Session.

ASP.NET fornece um controle considerável sobre onde as informações de estado da sessão acessadas usando a propriedade Session do HttpContext é realmente armazenada. Ele pode ser armazenado em cookies, em um banco de dados, na memória do servidor atual ou na memória de um servidor designado. A escolha é feita no arquivo de configuração do serviço.

O WCF fornece objetos extensíveis para o gerenciamento de estado. Objetos extensíveis são objetos que implementam IExtensibleObject<T>. Os objetos extensíveis mais importantes são ServiceHostBase e InstanceContext. ServiceHostBase permite que você mantenha o estado que todas as instâncias de todos os tipos de serviço no mesmo host podem acessar, enquanto InstanceContext permite manter o estado que pode ser acessado por qualquer código em execução na mesma instância de um tipo de serviço.

Aqui, o tipo TradingSystemde serviço tem um ServiceBehaviorAttribute que especifica que todas as chamadas da mesma instância do cliente WCF são roteadas para a mesma instância do tipo de serviço.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TradingSystem: ITradingService

A classe DealDatadefine o estado que pode ser acessado por qualquer código em execução na mesma instância de um tipo de serviço.

internal class DealData: IExtension<InstanceContext>
{
 public string DealIdentifier = null;
 public Trade[] Trades = null;
}

No código do tipo de serviço que implementa uma das operações do contrato de serviço, um DealData objeto de estado é adicionado ao estado da instância atual do tipo de serviço.

string ITradingService.BeginDeal()
{
 string dealIdentifier = Guid.NewGuid().ToString();
 DealData state = new DealData(dealIdentifier);
 OperationContext.Current.InstanceContext.Extensions.Add(state);
 return dealIdentifier;
}

Esse objeto de estado pode então ser recuperado e modificado pelo código que implementa outra das operações do contrato de serviço.

void ITradingService.AddTrade(Trade trade)
{
 DealData dealData =  OperationContext.Current.InstanceContext.Extensions.Find<DealData>();
 dealData.AddTrade(trade);
}

Enquanto ASP.NET fornece controle sobre onde as informações de estado na classe são realmente armazenadas, o HttpContext WCF, pelo menos em sua versão inicial, não fornece controle sobre onde objetos extensíveis são armazenados. Isso constitui o melhor motivo para selecionar o modo de compatibilidade ASP.NET para um serviço WCF. Se o gerenciamento de estado configurável for imperativo, optar pelo modo de compatibilidade ASP.NET permitirá que você use as funcionalidades da classe HttpContext da mesma forma que em ASP.NET, além de configurar onde são armazenadas as informações de estado gerenciadas através da classe HttpContext.

Segurança

As opções para proteger ASP.NET serviços Web são aquelas para proteger qualquer aplicativo IIS. Como os aplicativos WCF podem ser hospedados não apenas no IIS, mas também em qualquer executável .NET, as opções para proteger aplicativos WCF devem ser feitas independentemente das instalações do IIS. No entanto, os recursos fornecidos para serviços Web ASP.NET também estão disponíveis para serviços WCF executados no modo de compatibilidade ASP.NET.

Segurança: autenticação

O IIS fornece recursos para controlar o acesso a aplicativos pelos quais você pode selecionar acesso anônimo ou uma variedade de modos de autenticação: Autenticação do Windows, Autenticação Digest, Autenticação Básica e Autenticação de Passaporte do .NET. A opção autenticação do Windows pode ser usada para controlar o acesso aos serviços Web ASP.NET. No entanto, quando os aplicativos WCF são hospedados no IIS, o IIS deve ser configurado para permitir o acesso anônimo ao aplicativo, de modo que a autenticação possa ser gerenciada pelo próprio WCF, que dá suporte à autenticação do Windows entre várias outras opções. As outras opções que são internas incluem tokens de nome de usuário, certificados X.509, tokens SAML e cartão CardSpace, mas mecanismos de autenticação personalizados também podem ser definidos.

Segurança: representação

ASP.NET fornece um elemento de identidade pelo qual um serviço Web ASP.NET pode ser feito para representar um usuário específico ou quaisquer credenciais de usuário que sejam fornecidas com a solicitação atual. Esse elemento pode ser usado para configurar a representação em aplicativos do WCF em execução no modo de compatibilidade com o ASP.NET.

O sistema de configuração do WCF fornece seu próprio elemento de identidade para designar um usuário específico para imitar. Além disso, os clientes e serviços do WCF podem ser configurados de forma independente para imitação. Os clientes podem ser configurados para representar o usuário atual quando transmitem solicitações.

<behaviors>
     <behavior name="DerivativesCalculatorClientBehavior">
      <clientCredentials>
      <windows allowedImpersonationLevel="Impersonation"/>
      </clientCredentials>
     </behavior>
</behaviors>

As operações de serviço podem ser configuradas para representar quaisquer credenciais do usuário fornecidas com a solicitação atual.

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void Receive(Message input)

Segurança: autorização usando listas de controle de acesso

As ACLs (Listas de Controle de Acesso) podem ser usadas para restringir o acesso a arquivos .asmx. No entanto, as ACLs em arquivos .svc do WCF são ignoradas, exceto no modo de compatibilidade ASP.NET.

Segurança: Autorização baseada em função

A opção de Autenticação do Windows do IIS pode ser usada em conjunto com o elemento de autorização fornecido pela linguagem de configuração ASP.NET para facilitar a autorização baseada em função para ASP.NET serviços Web com base nos grupos do Windows aos quais os usuários são atribuídos. ASP.NET 2.0 introduziu um mecanismo de autorização mais geral baseado em função: provedores de função.

Provedores de função são classes que implementam uma interface básica para consultar as funções às quais um usuário é atribuído, mas cada provedor de função sabe como recuperar essas informações de uma fonte diferente. ASP.NET 2.0 fornece um provedor de funções que pode recuperar atribuições de função de um banco de dados do Microsoft SQL Server e outro que pode recuperar atribuições de função do Gerenciador de Autorização do Windows Server 2003.

O mecanismo do provedor de função pode ser usado de forma independente de ASP.NET em qualquer aplicativo .NET, incluindo um aplicativo WCF. A configuração de exemplo a seguir para um aplicativo WCF mostra como o uso de um provedor de função ASP.NET é uma opção selecionada por meio do ServiceAuthorizationBehavior.

<system.serviceModel>
     <services>
         <service name="Service.ResourceAccessServiceType"
             behaviorConfiguration="ServiceBehavior">
             <endpoint
              address="ResourceAccessService"
              binding="wsHttpBinding"
              contract="Service.IResourceAccessContract"/>
         </service>
     </services>
     <behaviors>
       <behavior name="ServiceBehavior">
       <serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
      </behavior>
     </behaviors>
</system.serviceModel>

Segurança: Autorização baseada em declarações

Uma das inovações mais importantes do WCF é seu suporte completo para autorizar o acesso a recursos protegidos com base em declarações. As reivindicações consistem em um tipo, um direito e um valor, como uma carteira de motorista, por exemplo. Faz um conjunto de reivindicações sobre o portador, uma das quais é a data de nascimento do portador. O tipo dessa declaração é data de nascimento, enquanto o valor da declaração é a data de nascimento do motorista. O direito que uma declaração confere no portador especifica o que o portador pode fazer com o valor da declaração. No caso da declaração da data de nascimento do motorista, o direito é a posse: o motorista possui essa data de nascimento, mas não pode, por exemplo, alterá-la. Autorização baseada em declaração inclui a autorização baseada em função, pois as funções são um tipo de declaração.

A autorização com base em declarações é realizada comparando um conjunto de declarações aos requisitos de acesso da operação e, dependendo do resultado dessa comparação, concedendo ou negando acesso à operação. No WCF, você pode especificar uma classe a ser usada para executar a autorização baseada em declarações, mais uma vez atribuindo um valor à ServiceAuthorizationManager propriedade de ServiceAuthorizationBehavior.

<behaviors>
     <behavior name='ServiceBehavior'>
     <serviceAuthorization
     serviceAuthorizationManagerType=
                   'Service.AccessChecker, Service' />
     </behavior>
</behaviors>

As classes usadas para executar a autorização baseada em declarações devem derivar de ServiceAuthorizationManager, que possui apenas um método para substituir: AccessCheck(). O WCF chama esse método sempre que uma operação do serviço é chamada e fornece um objeto OperationContext, que tem as declarações do usuário na propriedade ServiceSecurityContext.AuthorizationContext. O WCF faz o trabalho de montar declarações sobre o usuário a partir de qualquer token de segurança fornecido para autenticação, o que deixa para o sistema a tarefa de avaliar se essas declarações são suficientes para a operação em questão.

Esse WCF reúne automaticamente declarações de qualquer tipo de token de segurança é uma inovação altamente significativa, pois torna o código de autorização baseado nas declarações totalmente independentes do mecanismo de autenticação. Por outro lado, a autorização usando ACLs ou funções em ASP.NET está intimamente vinculada à autenticação do Windows.

Segurança: confidencialidade

A confidencialidade das mensagens trocadas com ASP.NET serviços Web pode ser assegurada no nível de transporte configurando o aplicativo no IIS para usar o HTTPS (Secure Hypertext Transfer Protocol). O mesmo pode ser feito para aplicativos WCF hospedados no IIS. No entanto, aplicativos WCF hospedados fora do IIS também podem ser configurados para usar um protocolo de transporte seguro. Mais importante, os aplicativos WCF também podem ser configurados para proteger as mensagens antes de serem transportadas, usando o protocolo WS-Security. Proteger apenas o corpo de uma mensagem usando WS-Security permite que ela seja transmitida confidencialmente entre intermediários antes de chegar ao seu destino final.

Globalização

A linguagem de configuração ASP.NET permite que você especifique a cultura para serviços individuais. O WCF não dá suporte a essa configuração, exceto no modo de compatibilidade ASP.NET. Para localizar um serviço WCF que não usa o modo de compatibilidade do ASP.NET, compile o tipo de serviço em assemblies específicos de cada cultura e configure pontos de extremidade separados para cada um deles.

Consulte também