확장 가능한 개체 패턴은 기존 런타임 클래스를 새 기능으로 확장하거나 개체에 새 상태를 추가하는 데 사용됩니다. 처리의 매우 다른 단계에서 동작을 사용할 수 있게 하는 확장은 확장 가능한 개체 중 하나에 연결되며, 이로 인해 사용자는 공통 확장 가능한 개체에 연결된 공유 상태 및 기능에 접근할 수 있습니다.
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 호출됩니다. 즉,(적절한 동기화를 가정) 확장은 AttachDetach사이에 있는 동안 컬렉션에서만 찾을 수 있습니다.
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)에는 4개의 확장 가능한 개체가 있습니다.
ServiceHostBase – 서비스 호스트의 기본 클래스입니다. 이 클래스의 확장은 ServiceHostBase 자체의 동작을 확장하거나 각 서비스에 대한 상태를 저장하는 데 사용할 수 있습니다.
InstanceContext – 이 클래스는 서비스 유형의 인스턴스를 서비스 런타임에 연결합니다. 인스턴스에 대한 정보와 InstanceContext가 포함하고 있는 ServiceHostBase에 대한 참조가 포함되어 있습니다. 이 클래스의 확장은 InstanceContext 동작을 확장하거나 각 서비스의 상태를 저장하는 데 사용할 수 있습니다.
OperationContext – 이 클래스는 런타임이 각 작업에 대해 수집하는 작업 정보를 나타냅니다. 여기에는 들어오는 메시지 헤더, 들어오는 메시지 속성, 들어오는 보안 ID 및 기타 정보와 같은 정보가 포함됩니다. 이 클래스의 확장은 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();
}
}
}