IgnoreDataMemberAttribute

A partir do .NET Framework 3.5 SP1 temos a possibilidade de suportar a serialização de tipos complexos em serviços WCF, mesmo que eles não estejam decorados com o atributo DataContractAttribute, DataMemberAttribute ou SerializableAttribute, permitindo o suporte à objetos POCO.

Quando trabalhamos nesta linha, não precisamos nos preocupar com os atributos já que, por padrão, todas as propriedades públicas serão serializadas. Já que o comportamento padrão faz com que todas as propriedades serão serializadas, como podemos determinar que uma delas não deve ser disponibilizada para os consumidores do serviço? Neste caso, temos que explicitamente dizer ao runtime do WCF para não serializar tal propriedade e, para isso, recorremos à utilização do atributo IgnoreDataMemberAttribute, contida no namespace System.Runtime.Serialization, aplicando-o nas propriedades que não queremos que esteja disponível, assim como é mostrado abaixo:

public class Usuario
{
    public string Nome { get; set; }

    [IgnoreDataMember]
    public string Password { get; set; }
}

Expondo serviços WCF através do .NET Service Bus

Depois da conta devidamente criada dentro do Windows Azure, podemos facilmente fazer uso das funcionalidades que ele nos fornece. Dentre essas funcionalidades temos o .NET Services e, dentro deste, um repositório de serviços chamado .NET Service Bus. Utilizando o WCF, podemos conectar duas aplicações que estão localizadas em diferentes locais, ultrapassando os limites de uma organização, utilizando a “ponte” que é o Service Bus.

Em termos de estrutura e criação de um serviço, nada muda em relação ao que já conhecemos. As pequenas mudanças são na configuração do mesmo, a começar pelo binding, já que devemos utilizar um dos relay bindings. Além disso, há um novo behavior chamado TransportClientEndpointBehavior, que nos permite configurar as credenciais de acesso, assim como é ilustrado na configuração do host logo abaixo:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name=”Host.Servico”>
        <endpoint
          address=”sb://servicebus.windows.net/services/[solucao]/[servico]”
          behaviorConfiguration=”bh”
          binding=”netTcpRelayBinding”
          contract=”Host.IContrato” />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name=”bh”>
          <transportClientEndpointBehavior
            credentialType=”UserNamePassword”>
            <clientCredentials>
              <userNamePassword
                 userName=”[username]” password=”[password]” />
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Outro ponto importante que devemos notar é o endereço. Neste CTP, o .NET Service Bus apenas suporta dois schemes: “sb” e “http”. O “http” para protocolo HTTP e o “sb” para todos os outros. De acordo com o modelo de nomenclatura, “servicebus.windows.net” é a raiz, e com isso os endereços devem seguir o seguinte formato: “[scheme]://servicebus.windows.net/services/[solucao]/[servico]/[nome]”. Em futuras versões ele suportará diferentes formatos na URI.

As tipos que utilizamos para expor/consumir serviços WCF em cima do .NET Service Bus, estão contidos no Assembly Microsoft.ServiceBus.dll  que, por sua vez, é instalado com o SDK do Microsoft .NET Services (CTP). Ao rodar o host, o serviço está exposto e pode ser consumido pelos clientes. Ao iniciar o cliente que consome este serviço, as mensagens passam agora pelo .NET Service Bus até chegar efetivamente ao serviço.

Utilizando Datasets em serviços

Muitas pessoas utilizam Datasets e, consequentemente, DataTables para representar sua estrutura de dados. Com isso, pode haver a necessidade de expor esse tipo de objeto através de serviços (WCF ou ASMX). Como o Dataset pode ser serializado em formato Xml, então podemos fazer uso dele nestes serviços.

O problema que há neste caso é que isso é uma má prática do ponto de vista de interoperabilidade e, em alguns casos, de performance. A estrutura Xml que representa o Dataset é complexa e difícil de ser representada em outras plataformas que não seja o próprio .NET. Além disso, devido também a complexidade dele, a tamanho do envelope SOAP fica muito maior em relação à arrays de objetos (DTOs). E, para finalizar, se voce utiliza o Dataset como estrutura dos dados na aplicação, voce pode indiretamente expor a sua estrutura interna para o mundo.

Sempre que possível opte pela utilização de classes que são desenhadas (exclusivamente ou não) para serem trocadas entre o serviço e os clientes. Já quando precisar retorna uma lista, opte pelos tradicionais arrays. Isso garantirá um payload muito mais leve e, além disso, irá garantir a interoperabilidade com as mais diversas plataformas.

Utilização de entidades LINQ To SQL em serviços

Estive lendo um artigo na MSDN Magazine chamado Flexible Data Access With LINQ To SQL And The Entity Framework, escrito pelo Anthony Sneed. O artigo aborda como expor entidades criadas pelos ORMs da Microsoft (LINQ To SQL e Entity Framework) através de serviços WCF.

O autor criou DTOs (que são baseados em POCO) semelhantes as entidades criadas pelo designer do ORM, fazendo um trabalho árduo que é o mapeamento entre os DTOs e as entidades geradas. Como o LINQ To SQL tem um suporte legal para mapeamento entre objetos POCOs e o banco de dados (via arquivos Xml), o Anthony mostra neste post como podemos fazer uso dos templates T4, criando classes em formato POCO ao invés de utilizar as próprias entidades geradas pelo LINQ To SQL.

KnownTypes dinâmicos

Para lidar com classes e suas derivações em serviços, o WCF disponibiliza um recurso chamado Known Types. Com ele, é possível ter um método que defina como retorno um tipo base e, em seu interior, criar e retornar tipos derivados.

Para expor os tipos derivados a partir deste recurso, como se pode ver no artigo mencionado acima, voce deverá decorar a Interface ou os métodos que ela possuir  (se quiser ser mais restritivo) com o atributo ServiceKnownTypeAttribute. No artigo podemos ver que os tipos derivados são declarados estaticamente. Caso voce queira tornar a configuração dos known types do serviço de forma dinamica, voce poderá criar um método que retorne os tipos que serão suportados pelo serviço, como é mostrado abaixo:

private static class ServiceContractHelper
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        List<Type> knownTypes = new List<Type>();
        knownTypes.Add(typeof(Fisica));
        knownTypes.Add(typeof(Juridica));

        return knownTypes;
    }
}

Para que essa técnica funcione, é necessário que voce defina a assinatura do método como é mostrado acima, podendo variar o nome. Em seguida precisamos vincular esta classe ao contrato e, para isso, utilizamos um dos overloads do construtor do atributo ServiceKnownTypeAttribute que, receberá uma string contendo o nome do método que fornecerá os tipos e, um Type representando o tipo da classe que fornece o método.

[ServiceContract]
[ServiceKnownType(“GetKnownTypes”, typeof(ServiceContractHelper))]
public interface IGerenciadorDeContatos
{
    //métodos
}

Criando certificados para teste

Algumas funcionalidades de segurança do WCF exigem que se utilize certificados para proteger a mensagem. Eu tenho escrito sobre algumas dessas funcionalidades aqui e, no download do código fonte, o certificado não está junto com o projeto. Com isso, ao rodar a aplicação, voce receberá uma exceção dizendo que não foi possível localizar este certificado. Isso aconteceu recentemente com o artigo sobre customização de autenticação e autorização e que o leitor Marco Tulio apontou aqui.

Neste artigo específico, para que voce consiga rodá-lo, o primeiro passo é criar um certificado de testes a partir do utilitário makecert.exe que, por sua vez, vem juntamente com o SDK do .NET Framework. Para utilizá-lo, basta definir algumas configurações necessárias para a geração do certificado, algo como é mostrado abaixo:

C:>makecert -sr LocalMachine -ss TrustedPeople -sky exchange -pe -a sha1 -n “CN=localhost” C:localhost.cer

Observação: Para entender cada uma dessas opções que o utilitário fornece, consulte este artigo.

Depois do certificado criado, então nos resta configurá-lo para que o serviço possa fazer uso dele. Ao abrir o arquivo de configuração do host, efetue a mudança do certificado, apontando para este que foi recém criado. O código ficará semelhante ao qual é mostrado abaixo:

<serviceCredentials>
  <serviceCertificate
    findValue=”localhost”
    storeLocation=”LocalMachine”
    storeName=”TrustedPeople”
    x509FindType=”FindBySubjectName” />
    <!– Outras Configurações –>
</serviceCredentials>

Depois disso, execute o host separadamente e atualize a referencia no projeto cliente para que a chave pública seja alterada.

Para finalizar, ainda falando do artigo que explora a customização da autenticação e autorização no WCF, é necessário alterar o path dos arquivos XML que estão dentro da classe/arquivo XmlSecurityHelper.

WCF Performance Counters II

Algum tempo atrás eu falei comentei aqui sobre vários performance counters que foram adicionados ao runtime do WCF, disponibilizando diversas informações a respeito da execução dos serviços, tais como: número de chamadas, transações, segurança, etc.

Como sabemos, podemos fazer uso do IIS como host de serviços WCF e, com isso, utilizar alguns performance counters exclusivos de aplicações Web, instalados juntamente com o ASP.NET. Esses performance counters mensuram, entre várias informações importantes, a quantidade de requisições para uma determinada aplicação ou para um worker process. Utilizar esses performance counters para mensurar requisições para serviços WCF não pode ser muito confiável.

Há funcionalidades que quando habilitadas nos serviços WCF, como é o caso das reliable messages, fazem com que várias outras requisições sejam efetuadas nos bastidores, garantindo com que este recurso funcione e, como já era de se esperar, representará mais do que uma “requisição ASP.NET”, não refletindo exatamente o que está ocorrendo naquele momento. Quando precisar mensurar alguma estatística de serviços WCF, independentemente de onde eles estejam sendo hospedados (Windows Service, IIS, etc.), sempre opte por utilizar os performance counters exclusivos, agrupando as informações através de contadores específicos para cada funcionalidade, como é caso dos contadores que contabilizam as reliable messages.

Liberando Streams

Há algum tempo escrevi um artigo sobre transferencia e codificação de dados no WCF. Quando optamos por utilizar o modelo streaming, há um cuidado extra que devemos tomar para efetuar o fechamento dele. Neste cenário sempre há o desafio de saber quando e quem fecha o stream e que foram abordadas no artigo mecionado acima.

Quando alguém envia um stream para o outro lado, este deverá permanecer aberto até que a transferencia seja concluída. Não temos problemas quando o stream é passado diretamente com parametro ou como retorno de uma operação. O problema começa a acontecer quando voce altera a mensagem para que, além do stream, informe dados adicionais, como é mostrado no artigo e ressalto aqui:

[MessageContract]
public class StreamData
{
    [MessageHeader]
    public string NomeDoArquivo;

    [MessageHeader]
    public int Tamanho;

    [MessageBodyMember]
    public Stream Conteudo;
}

Ao retornar esse objeto, o stream relacionado a ele ficará aberto, causando problemas futuros. O WCF possui uma propriedade chamada AutoDisposeParameters, que está acessível através do atributo OperationBehaviorAttribute. Essa propriedade que, por padrão é True, diz ao runtime do WCF para invocar o método Dispose de todos os parametros (input e output) e dos objetos de retorno que implementam a Interface IDisposable e, a partir de agora, conseguimos entender porque quando lidamos com a classe Stream diretamente (ou uma de suas derivadas), o stream é devidamente fechado.

Como já deve suspeitar, o que nos resta fazer é também implementar a Interface IDisposable na classe StreamData e, dentro do método Dispose, invocar o método Dispose dos membros internos, garantindo assim, que o arquivo que está sendo utilizado por essa classe, seja fechado quando o método retornar.

[MessageContract]
public class StreamData : IDisposable
{
    [MessageHeader]
    public string NomeDoArquivo;

    [MessageHeader]
    public int Tamanho;

    [MessageBodyMember]
    public Stream Conteudo;

    public void Dispose()
    {
        if (this.Conteudo != null)
            this.Conteudo.Dispose();
    }
}

Acesso anônimo à arquivos *.svc

Ao efetuar o deploy de uma aplicação que utiliza a configuração padrão de um projeto do tipo WCF Service (arquivos *.svc), obrigatoriamente voce precisa permitir o acesso anônimo ao diretório virtual. Caso essa configuração não seja realizada, ao tentar acessar o serviço uma exceção do tipo NotSupportedException será disparada:

Security settings for this service require ‘Anonymous’ Authentication but it is not enabled for the IIS application that hosts this service.

Habilitar a autenticação anônima resolve o problema, mas em alguns cenários isso não é aceitável. A forma de resolver isso é alinhar as configurações de autenticação do serviço (arquivo Web.config) com as configurações do diretório virtual. O primeiro passo é desabilitar o acesso anônimo no diretório virtual, permitindo apenas a autenticação Windows. Neste caso,  a configuração do binding deve ser definida como autenticação Windows, refletindo a mesma configuração do IIS; já quando o modo de seguraça estiver definida como TransportCredentialOnly que “desliga” o acesso anônimo ao serviço. Com a configuração abaixo já é possível acessar o serviço sem o acesso anônimo habilitado no IIS:

<bindings>
  <basicHttpBinding>
    <binding name=”bndConfig”>
      <security mode=”TransportCredentialOnly”>
        <transport clientCredentialType=”Windows”/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

Um outro detalhe importante, é que endpoints para publicação do documento WSDL também exigem a autenticação anônima, e se tiver este endpoint no serviço, a mesma exceção que vimos acima será disparada. Para contornar este problema, voce deverá utilizar as mesmas regras de configurações de autenticação para este endpoint mas, os bindings exclusivos para publicação de metadados (mex*) não possuem características de segurança que possam ser configuradas. Podemos configurar o endpoint que expõe os metadados a partir de bindings convencionais e, com isso, ter acesso à todas as configurações de segurança que o WCF fornece. Abaixo consta a configuração geral deste cenário:

<endpoint
    address=””
    binding=”basicHttpBinding”
    contract=”IService”
    bindingConfiguration=”bndConfig” />
<endpoint
    address=”mex”
    binding=”basicHttpBinding”
    contract=”IMetadataExchange”
    bindingConfiguration=”bndConfig” />

<bindings>
  <basicHttpBinding>
    <binding name=”bndConfig”>
      <security mode=”TransportCredentialOnly”>
        <transport clientCredentialType=”Windows”/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

.NET 3.5 SP1 GDR (Fixes)

Está disponível a partir deste link uma atualização para o .NET Framework 3.5 SP1. Esta atualização também faz algumas poucas mudanças no WCF e, entre elas, o envio correto do código de status do protocolo HTTP quando a autenticação via HTTP é inválida.

Como já foi mencionado neste kb, quando utilizamos um autenticador customizado no WCF, disparamos a exceção SecurityTokenValidationException para informar ao runtime que o usuário é inválido. Quando o runtime identifica essa exceção, ele traduz a mesma para o código 403 (Forbidden) do HTTP. A mudança que é realizada com esta atualização é que ao invés de retornar 403, passará a retornar o código 401 (Unauthorized), que acaba sendo mais coerente com a situação.