다음을 통해 공유


확장 가능한 개체

새 기능과 함께 기존 런타임 클래스를 확장하거나 새 상태를 개체에 추가하기 위해 확장명 가능한 개체 패턴이 사용됩니다. 확장명 가능한 개체 중 하나에 연결된 확장은 이 개체에서 액세스할 수 있는 확장명 가능한 일반 개체에 연결된 공유 상태 및 기능에 액세스하는 처리 시에 매우 다른 단계에서 동작을 활성화합니다.

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>인 클래스에 대해서만 확장이 정의될 수 있도록 합니다. AttachDetach는 집계 또는 분배 알림을 제공합니다.

구현에서 확장을 추가하고 소유자에서 제거할 수 있는 시기를 제한할 수 있습니다. 예를 들어 완전히 제거를 허용하지 않거나, 소유자 또는 확장이 특정 상태에 있을 때 확장 추가 또는 제거를 허용하지 않거나, 여러 소유자에 동시에 추가하는 것을 허용하지 않거나, 단일 추가 후에만 단일 제거를 허용할 수 있습니다.

IExtension<T>에서는 다른 관리되는 표준 인터페이스와의 상호 작용을 나타내지 않습니다. 특히 소유자 개체의 IDisposable.Dispose 메서드는 일반적으로 확장을 분리하지 않습니다.

확장이 컬렉션에 추가되면 컬렉션에 들어가기 전에 Attach가 호출됩니다. 확장이 컬렉션에서 제거되면 제거된 후 Detach가 호출됩니다. 이는 (적절한 동기화가 이루어진다는 가정 하에) 확장이 AttachDetach 사이에 있는 동안에만 컬렉션에서 찾을 수 있음을 의미합니다.

FindAll 또는 Find에 전달된 개체가 IExtension<T>일 필요는 없지만(예를 들어 아무 개체나 전달할 수 있음) 반환되는 확장은 IExtension<T>입니다.

컬렉션에 IExtension<T> 확장자가 없으면 Find는 null을 반환하고 FindAll는 빈 컬렉션을 반환합니다. 여러 확장이 IExtension<T>를 구현하는 경우 Find는 그중 하나를 반환합니다. FindAll에서 반환되는 값은 스냅샷입니다.

두 가지 주요 시나리오가 있습니다. 첫 번째 시나리오에서는 Extensions 속성을 개체에 상태를 삽입하는 형식 기반 사전으로 사용하여 다른 구성 요소에서 해당 형식으로 개체를 조회할 수 있게 합니다.

두 번째 시나리오에서는 AttachDetach 속성을 사용하여 개체가 이벤트 등록, 상태 전환 감시 등의 사용자 지정 동작에 참여할 수 있게 합니다.

IExtensionCollection<T> 인터페이스는 IExtension<T>을 형식별로 검색할 수 있는 IExtension<T> 개체의 컬렉션입니다. IExtensionCollection<T>.Find는 해당 형식의 IExtension<T> 중에서 최근 추가된 개체만 반환합니다.

Windows Communication Foundation의 확장 가능한 개체

WCF(Windows Communication Foundation)에는 네 가지 확장 가능한 개체가 있습니다.

  • ServiceHostBase – 서비스 호스트의 기본 클래스입니다. 이 클래스의 확장을 사용하여 ServiceHostBase 자체의 동작을 확장하거나 각 서비스의 상태를 저장할 수 있습니다.

  • InstanceContext – 이 클래스는 서비스 형식의 인스턴스를 서비스 런타임과 연결합니다. 인스턴스에 대한 정보와 InstanceContext의 포함 ServiceHostBase에 대한 참조가 들어 있습니다. 이 클래스의 확장을 사용하여 InstanceContext의 동작을 확장하거나 각 서비스의 상태를 저장할 수 있습니다.

  • OperationContext – 이 클래스는 런타임에서 각 작업에 대해 수집하는 작업 정보를 나타냅니다. 여기에는 들어오는 메시지 헤더, 들어오는 메시지 속성, 들어오는 보안 ID, 기타 정보 등이 포함됩니다. 이 클래스의 확장은 OperationContext의 동작을 확장하거나 각 작업의 상태를 저장할 수 있습니다.

  • IContextChannel – 이 인터페이스를 사용하면 WCF 런타임에 의해 작성된 채널 및 프록시에서 각 상태를 확인할 수 있습니다. 이 클래스의 확장은 IClientChannel의 동작을 확장하거나 이 동작을 사용하여 각 채널의 상태를 저장할 수 있습니다.

다음 코드 예제에서는 단순한 확장을 사용하여 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();
    }
  }
}

참고 항목