Compartir vía


Objetos extensibles

El patrón de objeto extensible se usa para ampliar las clases en tiempo de ejecución existentes con una nueva funcionalidad o para agregar un nuevo estado a un objeto. Las extensiones, asociadas a uno de los objetos extensibles, permiten comportamientos en fases muy diferentes del procesamiento para acceder al estado compartido y a la funcionalidad asociada a un objeto extensible común al que pueden acceder.

El patrón IExtensibleObject<T>

Hay tres interfaces en el patrón de objeto extensible: IExtensibleObject<T>, IExtension<T>y IExtensionCollection<T>.

La IExtensibleObject<T> interfaz se implementa mediante tipos que permiten IExtension<T> a los objetos personalizar su funcionalidad.

Los objetos extensibles permiten la agregación dinámica de IExtension<T> objetos. IExtension<T> Los objetos se caracterizan por la siguiente interfaz:

public interface IExtension<T>
where T : IExtensibleObject<T>
{
    void Attach(T owner);
    void Detach(T owner);
}

La restricción de tipos garantiza que las extensiones solo se pueden definir para las clases que son IExtensibleObject<T>. Attach y Detach proporcionan notificaciones de agregación o desagregación.

Es válido para que las implementaciones restrinjan cuando se pueden agregar y quitar de un propietario. Por ejemplo, puede denegar la eliminación por completo, no permitir agregar o quitar extensiones cuando el propietario o la extensión están en un estado determinado, no permitir agregar a varios propietarios simultáneamente o permitir una sola adición seguida de una sola eliminación.

IExtension<T> no implica ninguna interacción con otras interfaces administradas estándar. En concreto, el IDisposable.Dispose método del objeto owner no suele desasociar sus extensiones.

Cuando se agrega una extensión a la colección, se llama a Attach antes de que entre en la colección. Cuando se quita una extensión de la colección, se llama Detach después de quitarla. Esto significa que, suponiendo la sincronización adecuada, una extensión puede confiar en que solo se encontrará en la colección mientras esté entre Attach y Detach.

El objeto pasado a FindAll o Find no debe ser IExtension<T> (por ejemplo, puede pasar cualquier objeto), pero la extensión devuelta es .IExtension<T>

Si ninguna extensión de la colección es un IExtension<T>, Find devuelve nulo y FindAll devuelve una colección vacía. Si varias extensiones implementan IExtension<T>, Find devuelve una de ellas. El valor devuelto de FindAll es una captura.

Hay dos escenarios principales. El primer escenario usa la Extensions propiedad como diccionario basado en tipos para insertar el estado en un objeto para permitir que otro componente lo busque con el tipo .

En el segundo escenario se usan las Attach propiedades y Detach para permitir que un objeto participe en el comportamiento personalizado, como el registro de eventos, la inspección de transiciones de estado, etc.

La IExtensionCollection<T> interfaz es una colección de los IExtension<T> objetos que permiten recuperar el IExtension<T> objeto por su tipo. IExtensionCollection<T>.Find devuelve el objeto agregado más recientemente que es un IExtension<T> de ese tipo.

Objetos extensibles en Windows Communication Foundation

Hay cuatro objetos extensibles en Windows Communication Foundation (WCF):

  • ServiceHostBase : es la clase base para el host del servicio. Las extensiones de esta clase se pueden usar para ampliar el comportamiento del ServiceHostBase propio o para almacenar el estado de cada servicio.

  • InstanceContext : esta clase conecta una instancia del tipo del servicio con el tiempo de ejecución del servicio. Contiene información sobre la instancia así como una referencia al InstanceContext que contiene ServiceHostBase. Las extensiones de esta clase se pueden usar para ampliar el comportamiento de InstanceContext o para almacenar el estado de cada servicio.

  • OperationContext : esta clase representa la información de operación que el tiempo de ejecución recopila para cada operación. Esto incluye información como los encabezados de mensaje entrantes, las propiedades del mensaje entrante, la identidad de seguridad entrante y otra información. Las extensiones de esta clase pueden ampliar el comportamiento de OperationContext o almacenar el estado de cada operación.

  • IContextChannel : esta interfaz permite la inspección de cada estado de los canales y servidores proxy creados por el tiempo de ejecución de WCF. Las extensiones de esta clase pueden ampliar el comportamiento de IClientChannel o puede usarlo para almacenar el estado de cada canal.

En el ejemplo de código siguiente se muestra el uso de una extensión sencilla para realizar un seguimiento InstanceContext de los objetos.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

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()
        { _instanceId = Guid.NewGuid().ToString(); }

        public string InstanceId => _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();
        }
    }
}

Consulte también