Objetos extensíveis
O padrão de objeto extensível é usado para estender classes de runtime existentes com nova funcionalidade ou para adicionar um novo estado a um objeto. As extensões, anexadas a um dos objetos extensíveis, permitem comportamentos em estágios muito diferentes no processamento a fim de acessar o estado compartilhado e a funcionalidade anexada a um objeto extensível comum que podem acessar.
O padrão IExtensibleObject<T>
Há três interfaces no padrão de objeto extensível: IExtensibleObject<T>, IExtension<T>e IExtensionCollection<T>.
A interface IExtensibleObject<T> é implementada por tipos que permitem objetos IExtension<T> para personalizar sua funcionalidade.
Objetos extensíveis permitem a agregação dinâmica de objetos IExtension<T>. Os objetos IExtension<T> são caracterizados pela seguinte interface:
public interface IExtension<T>
where T : IExtensibleObject<T>
{
void Attach(T owner);
void Detach(T owner);
}
A restrição de tipo garante que as extensões só podem ser definidas para classes que são IExtensibleObject<T>. Attach e Detach fornecem uma notificação de agregação ou desagregação.
É válido que as implementações restrinjam quando podem ser adicionadas e removidas de um proprietário. Por exemplo, você pode não permitir a remoção inteiramente, não permitindo adicionar ou remover extensões quando o proprietário ou a extensão estiver em um determinado estado, não permitir a adição a vários proprietários simultaneamente ou permitir apenas uma única adição seguida por uma única remoção.
IExtension<T> não implica interações com outras interfaces gerenciadas padrão. Especificamente, o método IDisposable.Dispose no objeto proprietário normalmente não desanexa suas extensões.
Quando uma extensão é adicionada à coleção, Attach é chamada antes de entrar na coleção. Quando uma extensão é removida da coleção, Detach é chamada depois que ela é removida. Isso significa que (supondo a sincronização apropriada) uma extensão pode contar apenas com a localização na coleção enquanto ela está entre Attach e Detach.
O objeto passado para FindAll ou Find não precisa ser IExtension<T> (por exemplo, você pode passar qualquer objeto), mas a extensão retornada é um IExtension<T>.
Se nenhuma extensão na coleção for um IExtension<T>, Find retornará nulo e FindAll retornará uma coleção vazia. Se forem implementadas várias extensões IExtension<T>, Find retornará uma delas. O valor retornado de FindAll é um instantâneo.
Há dois cenários principais. O primeiro cenário usa a propriedade Extensions como um dicionário baseado em tipo para inserir o estado em um objeto para permitir que outro componente pesquise-a usando o tipo.
O segundo cenário usa as propriedades Attach e Detach para permitir que um objeto participe do comportamento personalizado, como registrar-se em eventos, observar transições de estado e assim por diante.
Uma interface IExtensionCollection<T> é uma coleção de objetos IExtension<T> que permitem a recuperação de IExtension<T> pelo seu tipo. IExtensionCollection<T>.Find retorna o objeto adicionado mais recentemente que é um IExtension<T> desse tipo.
Objetos extensíveis no Windows Communication Foundation
Há quatro objetos extensíveis no WCF (Windows Communication Foundation):
ServiceHostBase – Essa é a classe base para o host do serviço. As extensões dessa classe podem ser usadas para estender o comportamento do próprio ServiceHostBase ou para armazenar o estado de cada serviço.
InstanceContext – Essa classe conecta uma instância do tipo do serviço com o runtime do serviço. Ela contém informações sobre a instância, bem como uma referência aos InstanceContexts que contêm ServiceHostBase. As extensões dessa classe podem ser usadas para estender o comportamento do InstanceContext ou armazenar o estado de cada serviço.
OperationContext – Essa classe representa as informações de operação que o runtime coleta para cada operação. Isso inclui informações como os cabeçalhos de mensagem de entrada, as propriedades da mensagem de entrada, a identidade de segurança de entrada e outras informações. As extensões dessa classe podem estender o comportamento de OperationContext ou armazenar o estado para cada operação.
IContextChannel – Essa interface permite a inspeção de cada estado para os canais e proxies criados pelo runtime do WCF. As extensões dessa classe podem estender o comportamento de IClientChannel ou armazenar o estado para cada operação.
O exemplo de código a seguir mostra o uso de uma extensão simples para rastrear objetos InstanceContext.
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Text;
namespace Microsoft.WCF.Documentation
{
public class MyInstanceContextInitializer : IInstanceContextInitializer
{
public void Initialize(InstanceContext instanceContext, Message message)
{
MyInstanceContextExtension extension = new MyInstanceContextExtension();
//Add your custom InstanceContext extension that will let you associate state with this instancecontext
instanceContext.Extensions.Add(extension);
}
}
//Create an Extension that will attach to each InstanceContext and let it retrieve the Id or whatever state you want to associate
public class MyInstanceContextExtension : IExtension<InstanceContext>
{
//Associate an Id with each Instance Created.
String instanceId;
public MyInstanceContextExtension()
{ this.instanceId = Guid.NewGuid().ToString(); }
public String InstanceId
{
get
{ return this.instanceId; }
}
public void Attach(InstanceContext owner)
{
Console.WriteLine("Attached to new InstanceContext.");
}
public void Detach(InstanceContext owner)
{
Console.WriteLine("Detached from InstanceContext.");
}
}
public class InstanceInitializerBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters)
{ }
//Apply the custom IInstanceContextProvider to the EndpointDispatcher.DispatchRuntime
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
MyInstanceContextInitializer extension = new MyInstanceContextInitializer();
endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(extension);
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{ }
public void Validate(ServiceEndpoint endpoint)
{ }
}
public class InstanceInitializerBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(InstanceInitializerBehavior); }
}
protected override object CreateBehavior()
{
return new InstanceInitializerBehavior();
}
}
}