Estendendo distribuidores
Os dispatchers são responsáveis por extrair mensagens de entrada dos canais subjacentes, convertê-las em invocações de método no código do aplicativo e enviar os resultados novamente ao chamador. As extensões do Dispatcher permitem modificar esse processamento. Você pode implementar inspetores de mensagens ou parâmetros que inspecionam ou modificam o conteúdo de mensagens ou parâmetros. Você pode alterar a maneira como as mensagens são roteadas para operações ou fornecer alguma outra funcionalidade.
Este tópico descreve como usar as classes DispatchRuntime e DispatchOperation em um aplicativo de serviço do Windows Communication Foundation (WCF) para modificar o comportamento de execução padrão de um dispatcher ou para interceptar ou modificar mensagens, parâmetros ou retornar valores antes ou subsequente ao envio ou à recuperação da camada de canal. Para obter mais informações sobre o processamento de mensagens de runtime do cliente equivalente, confira Estendendo clientes. Para entender a função que os tipos IExtensibleObject<T> desempenham ao acessar o estado compartilhado entre vários objetos de personalização de runtime, confira Objetos Extensíveis.
Dispatchers
A camada de modelo de serviço executa a conversão entre o modelo de programação do desenvolvedor e a troca de mensagens subjacente, normalmente chamada de camada de canal. No WCF, os dispatchers de canal e ponto de extremidade (ChannelDispatcher e EndpointDispatcher, respectivamente) são os componentes de serviço responsáveis por aceitar novos canais, receber mensagens, expedição e invocação de operação e processamento de resposta. Objetos dispatcher são objetos receptores, mas implementações de contrato de retorno de chamada em serviços duplex também expõem seus objetos dispatcher para inspeção, modificação ou extensão.
O dispatcher de canal (e IChannelListener complementar) retira mensagens do canal subjacente e passa as mensagens para seus respectivos dispatchers de ponto de extremidade. Cada dispatcher de ponto de extremidade tem um DispatchRuntime que roteia mensagens para o DispatchOperation apropriado, que é responsável por chamar o método que implementa a operação. Várias classes de extensão opcionais e necessárias são invocadas ao longo do caminho. Este tópico explica como essas partes se encaixam e como você pode modificar propriedades e conectar seu próprio código para estender a funcionalidade base.
As propriedades do Dispatcher e os objetos de personalização modificados são inseridos usando objetos de comportamento de serviço, ponto de extremidade, contrato ou operação. Este tópico não descreve como usar comportamentos. Para obter mais informações sobre os tipos usados para inserir modificações do dispatcher, confira Configurando e estendendo o runtime com comportamentos.
O gráfico a seguir fornece uma exibição de alto nível dos itens de arquitetura em um serviço.
Dispatchers do Canal
Um objeto ChannelDispatcher é criado para associar um IChannelListener a um URI específico (chamado de URI de escuta) a uma instância de um serviço. Cada objeto ServiceHost pode ter muitos objetos ChannelDispatcher, cada um associado a apenas um ouvinte e URI de escuta. Quando uma mensagem chega, o ChannelDispatcher consulta cada um dos objetos associados EndpointDispatcher se o ponto de extremidade pode aceitar a mensagem e passa a mensagem para aquele que pode.
Todas as propriedades que controlam o tempo de vida e o comportamento de uma sessão de canal estão disponíveis para inspeção ou modificação no objeto ChannelDispatcher. Isso inclui inicializadores de canal personalizados, o ouvinte de canal, o host, o InstanceContext associado, e assim por diante.
Dispatchers de ponto de extremidade
O objeto EndpointDispatcher é responsável por processar mensagens de um ChannelDispatcher quando o endereço de destino de uma mensagem corresponde ao AddressFilter e a ação de mensagem corresponde à propriedade ContractFilter. Se dois objetos EndpointDispatcher puderem aceitar uma mensagem, o valor da propriedade FilterPriority determinará o ponto de extremidade de prioridade mais alta.
Use o EndpointDispatcher para adquirir os dois principais pontos de extensão do modelo de serviço – as classes DispatchRuntime e DispatchOperation – que você pode usar para personalizar o processamento do dispatcher. A classe DispatchRuntime permite que os usuários interceptem e estendam o dispatcher no escopo do contrato (ou seja, para todas as mensagens em um contrato). A classe DispatchOperation permite que os usuários interceptem e estendam o dispatcher em um escopo de operação (ou seja, para todas as mensagens em um contrato).
Cenários
Há vários motivos para estender o dispatcher:
Validação de mensagem personalizada. Os usuários podem querer impor que uma mensagem seja válida para um determinado esquema. Isso pode ser feito implementando as interfaces do interceptador de mensagens. Para obter um exemplo, confira Inspetores de Mensagens.
Registro em log de mensagens personalizado. Os usuários podem querer inspecionar e registrar um conjunto de mensagens de aplicativo que fluem por meio de um ponto de extremidade. Isso também pode ser feito com as interfaces do interceptador de mensagens.
Transformações de mensagens personalizadas. Os usuários podem aplicar determinadas transformações à mensagem no runtime (por exemplo, para controle de versão). Isso pode ser feito, novamente, com as interfaces do interceptador de mensagens.
Modelo de dados personalizado. Os usuários podem querer ter um modelo de dados ou serialização diferente daqueles com suporte por padrão no WCF (ou seja, System.Runtime.Serialization.DataContractSerializer, System.Xml.Serialization.XmlSerializer e mensagens brutas). Isso pode ser feito com o implemento das interfaces do formatador de mensagens. Para obter um exemplo, confira Formatador de operação e seletor de operação.
Validação de parâmetro personalizada Os usuários podem querer impor que os parâmetros tipado sejam válidos (em vez de XML). Isso pode ser feito usando as interfaces do inspetor de parâmetros.
Expedição de Operação Personalizada. Os usuários podem implementar a expedição em algo diferente de ação, por exemplo, no elemento body ou em uma propriedade de mensagem personalizada. Isso pode ser feito usando a interface IDispatchOperationSelector. Para obter um exemplo, confira Formatador de operação e seletor de operação.
Pool de objetos. Os usuários podem agrupar instâncias em vez de alocar uma nova para cada chamada. Isso pode ser implementado usando as interfaces do provedor de instância. Para obter um exemplo, confira Pooling.
Locação de instância. Os usuários podem implementar um padrão de concessão por tempo de vida, semelhante ao da comunicação remota .NET Framework. Isso pode ser feito usando as interfaces de tempo de vida do contexto de instância.
Tratamento personalizado de erros. Os usuários podem controlar como os erros locais são processados e como as falhas são comunicadas de volta aos clientes. Isso pode ser implementado usando as interfaces IErrorHandler.
Comportamentos de autorização personalizados. Os usuários podem implementar o controle de acesso personalizado estendendo as partes de tempo de execução contrato ou operação e adicionando verificações de segurança com base nos tokens presentes na mensagem. Isso pode ser feito usando o interceptador de mensagens ou interfaces do interceptador de parâmetros. Para obter exemplos, confira Extensibilidade de segurança.
Cuidado
Como a alteração das propriedades de segurança tem o potencial de comprometer a segurança dos aplicativos WCF, é altamente recomendável que você realize modificações relacionadas à segurança com cuidado e teste minuciosamente antes da implantação.
Validadores de runtime do WCF personalizados. Você pode instalar validadores personalizados que examinam serviços, contratos e associações para impor políticas de nível empresarial em relação aos aplicativos WCF. (Por exemplo, confira Como bloquear pontos de extremidade na empresa).
Usando a classe DispatchRuntime
Use a classe DispatchRuntime para modificar o comportamento padrão de um serviço ou ponto de extremidade individual ou para inserir objetos que implementam modificações personalizadas em um ou ambos os seguintes processos de serviço (ou processos de cliente no caso de um cliente duplex):
A transformação de mensagens de entrada em objetos e liberação desses objetos como invocações de método em um objeto de serviço.
A transformação de objetos recebidos da resposta a uma invocação de operação de serviço em mensagens de saída.
O DispatchRuntime permite que você intercepte e estenda o dispatcher de canal ou ponto de extremidade para todas as mensagens em um contrato específico, mesmo quando uma mensagem não é reconhecida. Quando chega uma mensagem que não corresponde a nenhuma declarada no contrato, ela é expedida para a operação retornada pela propriedade UnhandledDispatchOperation. Para interceptar ou estender todas as mensagens para uma operação específica, confira a classe DispatchOperation.
Há quatro áreas principais de extensibilidade do dispatcher expostas pela classe DispatchRuntime:
Os componentes de canal usam as propriedades do DispatchRuntime e as do dispatcher de canal associado retornadas pela propriedade ChannelDispatcher para personalizar como o dispatcher de canal aceita e fecha canais. Essa categoria inclui as propriedades ChannelInitializers e InputSessionShutdownHandlers.
Os componentes de mensagem são personalizados para cada mensagem processada. Essa categoria inclui as propriedades MessageInspectors, OperationSelector, Operations e ErrorHandlers.
Os componentes de instância personalizam a criação, o tempo de vida e o descarte de instâncias do tipo de serviço. Para obter mais informações sobre tempos de vida do objeto de serviço, confira a propriedade InstanceContextMode. Essa categoria inclui as propriedades InstanceContextInitializers e InstanceProvider.
Os componentes relacionados à segurança podem usar as seguintes propriedades:
SecurityAuditLogLocation indica onde os eventos de auditoria são gravados.
ImpersonateCallerForAllOperations controla se o serviço tentará representar usando as credenciais fornecidas pela mensagem de entrada.
MessageAuthenticationAuditLevel controla se os eventos de autenticação de mensagens com êxito são gravados no log de eventos especificado pelo SecurityAuditLogLocation.
PrincipalPermissionMode controla como a propriedade CurrentPrincipal é definida.
ServiceAuthorizationAuditLevel especifica como a auditoria de eventos de autorização é executada.
SuppressAuditFailure especifica se exceções não críticas que ocorrem durante o processo de registro em log devem ser suprimidas.
Tipicamente, os objetos de extensão personalizados são atribuídos a uma propriedade DispatchRuntime ou inseridos em uma coleção por um comportamento de serviço (um objeto que implementa IServiceBehavior), um comportamento de contrato (um objeto que implementa IContractBehavior) ou um comportamento de ponto de extremidade (um objeto que implementa IEndpointBehavior). Então o objeto de comportamento de instalação é adicionado à coleção apropriada de comportamentos de forma programática ou implementando um objeto personalizado BehaviorExtensionElement para permitir que o comportamento seja inserido usando um arquivo de configuração de aplicativo.
Os clientes duplex (clientes que implementam um contrato de retorno de chamada especificado por um serviço duplex) também têm um objeto DispatchRuntime que pode ser acessado usando a propriedade CallbackDispatchRuntime.
Usando a classe DispatchOperation
A classe DispatchOperation é o local para modificações de tempo de execução e o ponto de inserção para extensões personalizadas que têm como escopo apenas uma operação de serviço. (Para modificar o comportamento de tempo de execução do serviço para todas as mensagens em um contrato, use a classe DispatchRuntime.)
Instale as modificações DispatchOperation usando um objeto de comportamento de serviço personalizado.
Use a propriedade Operations para localizar o objeto DispatchOperation que representa uma operação de serviço específica.
As propriedades a seguir controlam a execução do runtime no nível da operação:
As propriedades Action, ReplyAction, FaultContractInfos, IsOneWay, IsTerminating e Name obtêm os respectivos valores para a operação.
TransactionAutoComplete e TransactionRequired especificam o comportamento da transação.
As propriedades ReleaseInstanceBeforeCall e ReleaseInstanceAfterCall controlam o tempo de vida do objeto de serviço definido pelo usuário em relação à InstanceContext.
As propriedades DeserializeRequest, SerializeReply e Formatter habilitam o controle explícito sobre a conversão de mensagens em objetos e objetos em mensagens.
A propriedade Impersonation especifica o nível de representação da operação.
A propriedade CallContextInitializers insere extensões de contexto de chamada personalizadas para a operação.
A propriedade AutoDisposeParameters controla quando objetos de parâmetro são destruídos.
A propriedade Invoker para inserir um objeto de invocador personalizado.
A propriedade ParameterInspectors permite inserir um inspetor de parâmetro personalizado que você pode usar para inspecionar ou modificar parâmetros e valores retornados.