拡張可能なオブジェクト パターンは、既存のランタイム クラスを新しい機能で拡張したり、オブジェクトに新しい状態を追加したりするために使用されます。 拡張は、拡張可能なオブジェクトのいずれかにアタッチされ、処理の非常に異なる段階で動作を有効にして、アクセスできる共通の拡張可能オブジェクトにアタッチされた共有状態と機能にアクセスします。
IExtensibleObject<T> パターン
拡張可能なオブジェクト パターンには、 IExtensibleObject<T>、 IExtension<T>、 IExtensionCollection<T>の 3 つのインターフェイスがあります。
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 は、集計または集計解除の通知を提供します。
実装では、所有者から追加および削除できるタイミングを制限することが有効です。 たとえば、削除を完全に禁止したり、所有者または拡張機能が特定の状態のときに拡張機能の追加や削除を禁止したり、複数の所有者に同時に追加することを禁止したり、1 回の追加と 1 回の削除のみを許可することができます。
IExtension<T> は、他の標準マネージド インターフェイスとの対話を意味するものではありません。 具体的には、所有者オブジェクトの IDisposable.Dispose メソッドは、通常、その拡張機能をデタッチしません。
拡張機能がコレクションに追加されると、コレクションに入る前に Attach が呼び出されます。 拡張機能がコレクションから削除されると、 Detach は削除後に呼び出されます。 つまり、(適切な同期を想定して) 拡張機能は、 Attach と Detachの間にコレクション内でのみ検出されることをカウントできます。
FindAllまたはFindに渡されるオブジェクトはIExtension<T>する必要はありませんが (たとえば、任意のオブジェクトを渡すことができます)、返される拡張機能はIExtension<T>です。
コレクション内に拡張子が IExtension<T>でない場合、 Find は null を返し、 FindAll は空のコレクションを返します。 複数の拡張機能が IExtension<T>を実装している場合、 Find はそのうちの 1 つを返します。 FindAllから返される値はスナップショットです。
主に 2 つのシナリオがあります。 最初のシナリオでは、 Extensions プロパティを型ベースのディクショナリとして使用してオブジェクトに状態を挿入し、別のコンポーネントが型を使用して検索できるようにします。
2 番目のシナリオでは、 Attach プロパティと Detach プロパティを使用して、イベントの登録、状態遷移の監視などのカスタム動作にオブジェクトを参加させます。
IExtensionCollection<T> インターフェイスは、その型でIExtension<T>を取得できるIExtension<T> オブジェクトのコレクションです。 IExtensionCollection<T>.Find は、その型の IExtension<T> である最後に追加されたオブジェクトを返します。
Windows Communication Foundation の拡張可能オブジェクト
Windows Communication Foundation (WCF) には、次の 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();
}
}
}