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