Поделиться через


Расширяемые объекты

Шаблон расширяемого объекта используется для расширения существующих классов среды выполнения с новыми функциями или добавления нового состояния в объект. Расширения, подключенные к одному из расширяемых объектов, обеспечивают поведение на очень разных этапах обработки для доступа к общему состоянию и функциональным возможностям, подключенным к общему расширяемым объекту, к которому они могут получить доступ.

Шаблон IExtensibleObject<T>

Существует три интерфейса в расширяемом шаблоне объектов: IExtensibleObject<T>, IExtension<T>и IExtensionCollection<T>.

Интерфейс IExtensibleObject<T> реализуется типами, позволяющими IExtension<T> объектам настраивать их функциональные возможности.

Расширяемые объекты позволяют динамически агрегировать IExtension<T> объекты. IExtension<T> Объекты характеризуются следующим интерфейсом:

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

Ограничение типа гарантирует, что расширения могут быть определены только для классов, которые являются IExtensibleObject<T>. Attach и Detach предоставляют уведомление об агрегировании или дезагрегировании.

Это приемлемо для реализаций ограничивать условия, при которых они могут быть добавлены или удалены у владельца. Например, вы можете полностью запретить удаление, запрещая добавлять или удалять расширения, когда владелец или расширение находятся в определенном состоянии, запрещать добавлять к нескольким владельцам одновременно или разрешать только одно добавление, за которым следует одно удаление.

IExtension<T> не подразумевает никаких взаимодействий с другими стандартными управляемыми интерфейсами. В частности, IDisposable.Dispose метод объекта владельца обычно не отсоединяет его расширения.

При добавлении расширения в коллекцию Attach вызывается перед добавлением в коллекцию. Когда расширение удаляется из коллекции, Detach вызывается после его удаления. Это означает , что (при условии соответствующей синхронизации) расширение может рассчитывать только на то, что оно найдено в коллекции, пока оно находится между Attach и Detach.

Объект, переданный FindAll или Find не должен быть IExtension<T> (например, можно передать любой объект), но возвращенное расширение является объектом IExtension<T>.

Если расширение в коллекции не является IExtension<T>, Find возвращает значение NULL и FindAll возвращает пустую коллекцию. Если несколько расширений реализуют IExtension<T>, Find возвращает одно из них. Возвращаемое из FindAll значение является снимком состояния.

Существует два основных сценария. Первый сценарий использует Extensions свойство в качестве словаря на основе типов для вставки состояния объекта, чтобы разрешить другому компоненту искать его с помощью типа.

Во втором сценарии используются Attach свойства и Detach свойства, позволяющие объекту участвовать в пользовательском поведении, таком как регистрация событий, просмотр переходов состояния и т. д.

Интерфейс IExtensionCollection<T> представляет собой коллекцию объектов IExtension<T>, которые позволяют извлекать IExtension<T> по его типу. IExtensionCollection<T>.Find возвращает последний добавленный объект, который является объектом IExtension<T> этого типа.

Расширяемые объекты в Windows Communication Foundation

В Windows Communication Foundation (WCF) есть четыре расширяемых объекта:

  • ServiceHostBase — это базовый класс для хоста службы. Расширения этого класса можно использовать для расширения поведения ServiceHostBase самой службы или хранения состояния для каждой службы.

  • InstanceContext — этот класс подключает экземпляр типа службы к среде выполнения службы. Он содержит сведения об экземпляре, а также ссылку на InstanceContextсодержащий ServiceHostBaseобъект. Расширения этого класса можно использовать для расширения поведения InstanceContext или хранения состояния для каждой службы.

  • OperationContext — Этот класс представляет сведения об операции, собираемые средой выполнения для каждой операции. Сюда входят такие сведения, как заголовки входящих сообщений, свойства входящих сообщений, входящие удостоверения безопасности и другие сведения. Расширения этого класса могут расширить поведение OperationContext или сохранить состояние для каждой операции.

  • IContextChannel — этот интерфейс позволяет проверять каждое состояние для каналов и прокси-серверов, созданных средой выполнения WCF. Расширения этого класса могут расширить поведение IClientChannel или использовать его для хранения состояния для каждого канала.

В следующем примере кода показано использование простого расширения для отслеживания InstanceContext объектов.

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();
        }
    }
}

См. также