Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este tópico discute os estados e transições que os canais têm, os tipos usados para estruturar estados de canal e como implementá-los.
Computadores e canais de estado
Objetos que lidam com a comunicação, por exemplo, soquetes, geralmente apresentam um computador de estado cujas transições de estado estão relacionadas à alocação de recursos de rede, à criação ou aceitação de conexões, ao fechamento de conexões e ao encerramento da comunicação. O computador de estado do canal fornece um modelo uniforme dos estados de um objeto de comunicação que abstrai a implementação subjacente desse objeto. A ICommunicationObject interface fornece um conjunto de estados, métodos de transição de estado e eventos de transição de estado. Todos os canais, alocadores de canal e ouvintes de canal implementam a máquina de estado do canal.
Os eventos Closed, Closing, Faulted, Opened e Opening sinalizam um observador externo após uma transição de estado.
Os métodos Abortar, Fechar e Abrir (e seus equivalentes assíncronos) causam transições de estado.
A propriedade state retorna o estado atual conforme definido por CommunicationState:
ICommunicationObject, CommunicationObject e States e State Transition
Um ICommunicationObject começa no estado Criado, onde suas várias propriedades podem ser configuradas. Uma vez no estado Aberto, o objeto pode ser usado para enviar e receber mensagens, mas suas propriedades são consideradas imutáveis. Uma vez no estado Fechamento, o objeto não pode mais processar novas solicitações de envio ou recebimento, mas as solicitações existentes têm a chance de ser concluídas até que o tempo limite de Fechamento seja atingido. Se ocorrer um erro irrecuperável, o objeto fará a transição para o estado com falha em que pode ser inspecionado para obter informações sobre o erro e, por fim, fechado. Quando está no estado Closed, o objeto atingiu essencialmente o fim da máquina de estado. Depois que um objeto faz a transição de um estado para o outro, ele não volta para um estado anterior.
O diagrama a seguir mostra os ICommunicationObject estados e as transições de estado. As transições de estado podem ser causadas pela chamada de um dos três métodos: Abort, Open ou Close. Elas também podem ser causadas chamando outros métodos específicos da implementação. A transição para o estado com falha pode ocorrer como resultado de erros ao abrir ou depois de ter aberto o objeto de comunicação.
Cada ICommunicationObject começa no estado Created. Nesse estado, um aplicativo pode configurar o objeto definindo suas propriedades. Depois que um objeto estiver em um estado diferente de Created, ele será considerado imutável.
Figura 1. A máquina de estado ICommunicationObject.
O WCF (Windows Communication Foundation) fornece uma classe base abstrata chamada CommunicationObject que implementa ICommunicationObject e o computador de estado do canal. O gráfico a seguir é um diagrama de estado modificado que é específico para CommunicationObject. Além da máquina de estado ICommunicationObject, mostra o momento em que métodos adicionais CommunicationObject são invocados.
Figura 2. A implementação CommunicationObject da máquina de estado ICommunicationObject, incluindo chamadas para eventos e métodos protegidos.
Eventos ICommunicationObject
CommunicationObject expõe os cinco eventos definidos por ICommunicationObject. Esses eventos são projetados para que o código que utiliza o objeto de comunicação seja notificado sobre transições de estado. Conforme mostrado na Figura 2 acima, cada evento é acionado uma vez depois que o estado do objeto faz a transição para o estado nomeado pelo evento. Todos os cinco eventos são do EventHandler tipo que é definido como:
public delegate void EventHandler(object sender, EventArgs e);
Na implementação CommunicationObject, o remetente é o próprio CommunicationObject ou o que foi passado como remetente para o construtor CommunicationObject (se a sobrecarga desse construtor foi usada). O parâmetro EventArgs, eé sempre EventArgs.Empty.
Retornos de chamada de objeto derivado
Além dos cinco eventos, CommunicationObject declara oito métodos virtuais protegidos projetados para permitir que um objeto derivado seja chamado antes e depois que ocorrem transições de estado.
Os métodos CommunicationObject.Open e CommunicationObject.Close têm três retornos de chamada associados a cada um. Por exemplo, correspondente a CommunicationObject.Open há CommunicationObject.OnOpening, CommunicationObject.OnOpene CommunicationObject.OnOpened. Estão associados a CommunicationObject.Close os métodos CommunicationObject.OnClose, CommunicationObject.OnClosing e CommunicationObject.OnClosed.
Da mesma forma, o CommunicationObject.Abort método tem um correspondente CommunicationObject.OnAbort.
Enquanto CommunicationObject.OnOpen, CommunicationObject.OnClose, e CommunicationObject.OnAbort não têm nenhuma implementação padrão, os outros callbacks têm uma implementação padrão que é necessária para a correção da máquina de estados. Se você substituir esses métodos, certifique-se de chamar a implementação base ou substituí-la corretamente.
CommunicationObject.OnOpening, CommunicationObject.OnClosing e CommunicationObject.OnFaulted disparam os eventos correspondentes CommunicationObject.Opening, CommunicationObject.Closing e CommunicationObject.Faulted. CommunicationObject.OnOpened e CommunicationObject.OnClosed definem o estado do objeto como Aberto e Fechado, respectivamente, e então acionam os eventos correspondentes CommunicationObject.Opened e CommunicationObject.Closed.
Métodos de transição de estado
CommunicationObject fornece implementações de Abort, Close e Open. Ele também fornece um método Fault que causa uma transição de estado para o estado Faulted. A Figura 2 mostra o ICommunicationObject computador de estado com cada transição rotulada pelo método que o causa (transições sem rótulo ocorrem dentro da implementação do método que causou a última transição rotulada).
Observação
Todas as implementações CommunicationObject de obtenção/definição do estado de comunicação são sincronizadas por thread.
Construtor
CommunicationObject fornece três construtores, todos os quais deixam o objeto no estado Criado. Os construtores são definidos como:
O primeiro construtor é um construtor sem parâmetros que delega à sobrecarga do construtor que usa um objeto :
protected CommunicationObject() : this(new object()) { … }
O construtor que usa um objeto usa esse parâmetro como o objeto a ser bloqueado ao sincronizar o acesso ao estado do objeto de comunicação:
protected CommunicationObject(object mutex) { … }
Por fim, um terceiro construtor usa um parâmetro adicional que é usado como o argumento remetente quando ICommunicationObject os eventos são acionados.
protected CommunicationObject(object mutex, object eventSender) { … }
Os dois construtores anteriores definem o remetente para isso.
Método Open
Pré-condição: o estado é criado.
Pós-condição: State é Opened ou Faulted. Pode gerar uma exceção.
O método Open() tentará abrir o objeto de comunicação e definir o estado como Aberto. Se encontrar um erro, ele definirá o estado como Faulted.
O método primeiro verifica se o estado atual é Created. Se o estado atual for Opening ou Opened, ele gerará um InvalidOperationException. Se o estado atual for Closing ou Closed, ele gerará um CommunicationObjectAbortedException se o objeto tiver sido encerrado e, caso contrário, ObjectDisposedException. Se o estado atual for Faulted, ele gerará um CommunicationObjectFaultedException.
Em seguida, ele define o estado como Abrir e chama OnOpening() (que gera o evento de abertura), OnOpen() e OnOpened() nessa ordem. OnOpened() define o estado como Aberto e aciona o evento Aberto. Se qualquer um deles lançar uma exceção, Open() chamará Fault() e permitirá que a exceção se propague. O diagrama a seguir mostra o processo "Open" em mais detalhes.
Substitua o método OnOpen para implementar a lógica aberta personalizada, como abrir um objeto de comunicação interna.
Método Close
Pré-condição: Nenhum.
Pós-condição: State é Closed. Pode gerar uma exceção.
O método Close() pode ser chamado em qualquer estado. Ele tenta fechar o objeto normalmente. Se um erro for encontrado, ele encerrará o objeto. O método não fará nada se o estado atual for Closing ou Closed. Caso contrário, ele definirá o estado como Closing. Se o estado original for Created, Opening ou Faulted, ele chamará Abort() (consulte o diagrama a seguir). Se o estado original for Opened, ele chamará OnClosing() (que gera o evento Closing), OnClose() e OnClosed() nessa ordem. Se algum deles gerar uma exceção, Close() chamará Abort() e permitirá que a exceção seja gerada. OnClosed() define o estado como Closed e aciona o evento Closed. O diagrama a seguir mostra o processo Close com mais detalhes.
Substitua o método OnClose para implementar a lógica de fechamento personalizada, como fechar um objeto de comunicação interna. Toda a lógica de fechamento gracioso que pode bloquear por um longo tempo (por exemplo, devido à espera pela resposta do outro lado) deve ser implementada em OnClose() porque aceita um parâmetro de tempo limite e porque essa função não é chamada como parte de Abort().
Abortar
Pré-condição: Nenhum.
Pós-condição: State é Closed. Pode gerar uma exceção.
O método Abort() não fará nada se o estado atual for Fechado ou se o objeto tiver sido encerrado antes (por exemplo, possivelmente por ter Abort() executado em outro thread). Caso contrário, ele define o estado como Fechamento e chama OnClosing() (que gera o evento de fechamento), OnAbort() e OnClosed() nessa ordem (não chama OnClose porque o objeto está sendo encerrado, não fechado). OnClosed() define o estado como Closed e aciona o evento Closed. Se alguma delas gerar uma exceção, ela será lançada novamente para o chamador de Abort. As implementações de OnClosing(), OnClosed() e OnAbort() não devem bloquear (por exemplo, durante operações de entrada/saída). O diagrama a seguir mostra o processo de Anulação com mais detalhes.
Substitua o método OnAbort para implementar lógica de encerramento personalizada, como encerrar um objeto de comunicação interna.
Falha
O método Fault é específico ao CommunicationObject e não faz parte da interface ICommunicationObject. Ele está incluído aqui para fins de integridade.
Pré-condição: Nenhum.
Pós-condição: State é Faulted. Pode gerar uma exceção.
O método Fault() não fará nada se o estado atual for Faulted ou Closed. Caso contrário, ele definirá o estado como Faulted e chamará OnFaulted(), o que gera o evento Faulted. Se OnFaulted gerar uma exceção, ele será relançado.
Métodos ThrowIfXxx
CommunicationObject tem três métodos protegidos que podem ser usados para gerar exceções se o objeto estiver em um estado específico.
ThrowIfDisposed gerará uma exceção se o estado for Closing, Closed ou Faulted.
ThrowIfDisposedOrImmutable gerará uma exceção se o estado não for Criado.
ThrowIfDisposedOrNotOpen gerará uma exceção se o estado não estiver Aberto.
As exceções geradas dependem do estado. A tabela a seguir mostra os estados diferentes e o tipo de exceção correspondente gerado chamando um ThrowIfXxx que gera esse estado.
| Estado | Abort foi chamado? | Exceção |
|---|---|---|
| Criado | Não aplicável | System.InvalidOperationException |
| Abertura | Não aplicável | System.InvalidOperationException |
| Aberto | Não aplicável | System.InvalidOperationException |
| Fechamento | Sim | System.ServiceModel.CommunicationObjectAbortedException |
| Fechamento | Não | System.ObjectDisposedException |
| Fechado | Sim | System.ServiceModel.CommunicationObjectAbortedException no caso de um objeto ter sido fechado por uma chamada anterior e explícita de Abort. Se você chamar Close no objeto, um System.ObjectDisposedException será gerado. |
| Fechado | Não | System.ObjectDisposedException |
| Com defeito | Não aplicável | System.ServiceModel.CommunicationObjectFaultedException |
Tempos limite
Vários dos métodos discutidos aceitam parâmetros de timeout. Eles são Close, Open (determinadas sobrecargas e versões assíncronas), OnClose e OnOpen. Esses métodos são projetados para permitir operações longas (por exemplo, bloqueio na entrada/saída enquanto se fecha uma conexão de forma adequada), para que o parâmetro de tempo limite indique quanto tempo essas operações podem levar antes de serem interrompidas. As implementações de qualquer um desses métodos devem usar o valor de tempo limite fornecido para garantir que ele retorne ao chamador dentro desse tempo limite. As implementações de outros métodos que não levam um tempo limite não são projetadas para operações prolongadas e não devem bloquear a entrada/saída.
A exceção é as sobrecargas Open() e Close() que não aceitam um tempo de espera. Eles usam um valor de tempo limite padrão fornecido pela classe derivada. CommunicationObject expõe duas propriedades abstratas protegidas nomeadas DefaultCloseTimeout e DefaultOpenTimeout definidas como:
protected abstract TimeSpan DefaultCloseTimeout { get; }
protected abstract TimeSpan DefaultOpenTimeout { get; }
Uma classe derivada implementa essas propriedades para fornecer o tempo limite padrão para as sobrecargas Open() e Close() que não exigem um valor de tempo limite. Em seguida, as implementações Open() e Close() delegam para a sobrecarga que usa um tempo limite, passando a ele o valor de tempo limite padrão, por exemplo:
public void Open()
{
this.Open(this.DefaultOpenTimeout);
}
IDefaultCommunicationTimeouts
Essa interface possui quatro propriedades de leitura exclusiva que fornecem valores padrão de tempo limite para as operações de abertura, envio, recebimento e fechamento. Cada implementação é responsável por obter os valores padrão de qualquer maneira apropriada. Como conveniência, ChannelFactoryBase e ChannelListenerBase padrão esses valores para 1 minuto cada.