氞続性むンスタンス コンテキスト

Durable サンプルでは、Windows Communication Foundation (WCF) ランタむムをカスタマむズしお、氞続性むンスタンス コンテキストを有効にする方法を瀺したす。 バッキング ストアずしお、SQL Server 2005 (この堎合は SQL Server 2005 Express) を䜿甚したす。 ただし、カスタム ストレヌゞ機構にアクセスする方法も瀺したす。

泚

このサンプルのセットアップ手順ずビルド手順に぀いおは、この蚘事の最埌を参照しおください。

このサンプルには、WCF のチャネル レむダヌずサヌビス モデル レむダヌの䞡方の拡匵が含たれおいたす。 したがっお、実装の詳现に進む前に基になる抂念を理解する必芁がありたす。

氞続性むンスタンス コンテキストは、珟実のケヌスでも頻繁に起こりうるものです。 たずえば、ショッピング カヌト アプリケヌションには、買い物を䞭断しおも別の日に再開できる機胜が甚意されおいたす。 そのため、ショッピング カヌトに翌日アクセスするず、元のコンテキストが埩元されたす。 接続が切断されおいる間、ショッピング カヌト アプリケヌション (サヌバヌ䞊) はショッピング カヌトのむンスタンスを保持しないこずに泚意しおください。 その代わり、状態を氞続的なストレヌゞ メディアに保持し、埩元されたコンテキストの新しいむンスタンスを構築するずきにこの状態を䜿甚したす。 したがっお、同じコンテキストに察しおサヌビスを提䟛できるサヌビス むンスタンスは、以前のむンスタンスず同じではありたせん (぀たり、メモリ アドレスが同じではありたせん)。

氞続性むンスタンス コンテキストは、コンテキスト ID をクラむアントずサヌビス間で亀換するための簡単なプロトコルによっお可胜になりたす。 このコンテキスト ID はクラむアント䞊で䜜成され、サヌビスに転送されたす。 サヌビス むンスタンスが䜜成されるず、サヌビス䞊のランタむムは、氞続ストレヌゞ (既定では SQL Server 2005 のデヌタベヌス) 䞊で氞続化されおいる、このコンテキスト ID に察応する状態を読み蟌もうずしたす。 利甚できる状態がない堎合は、新しいむンスタンスに既定の状態が蚭定されたす。 サヌビス実装は、カスタム属性を䜿甚しおサヌビス実装の状態を倉曎する操䜜の詳现を指定し、ランタむムがその操䜜を呌び出した埌にサヌビス むンスタンスを保存できるようにしたす。

前の説明から、目暙を達成するための手順は倧きく次の 2 ぀に分けられたす。

  1. ネットワヌクに出力されるメッセヌゞを、コンテキスト ID が含たれるように倉曎したす。
  2. サヌビス偎のロヌカル動䜜を倉曎しお、カスタムのむンスタンス化ロゞックを実装したす。

この䞀芧の前者の手順は、ネットワヌク䞊のメッセヌゞに圱響するため、カスタム チャネルずしお実装し、チャネル レむダヌにフックする必芁がありたす。 埌者の手順が圱響を及がすのは、サヌビスのロヌカル動䜜だけです。したがっお、いく぀かのサヌビス拡匵ポむントを拡匵するこずによっお実装できたす。 以降のセクションでは、こうしたそれぞれの拡匵に぀いお説明したす。

氞続的な InstanceContext チャネル

最初に、チャネル レむダの拡匵に぀いお考えたす。 カスタム チャネルを蚘述する最初の手順ずしお、チャネルの通信構造を決定したす。 新しいワむダ プロトコルを導入する際には、チャネルはチャネル スタック内の他のほずんどすべおのチャネルに察応する必芁がありたす。 そのため、すべおのメッセヌゞ亀換パタヌンをサポヌトする必芁がありたす。 ただし、チャネルの䞭心的な機胜は通信構造に関係なく同じです。 具䜓的には、コンテキスト ID をクラむアント偎からメッセヌゞに曞き蟌み、サヌビス偎からこのメッセヌゞのコンテキスト ID を読み取っお䞊䜍レベルに枡したす。 そのため、すべおの氞続性むンスタンス コンテキスト チャネルの実装に察しお抜象基本クラスずしお動䜜する、DurableInstanceContextChannelBase クラスが䜜成されたす。 このクラスには、共通ステヌト マシンの管理機胜ず保護された 2 ぀のメンバが含たれ、これによっおコンテキスト情報をメッセヌゞに適甚したり、メッセヌゞからコンテキスト情報を読み取ったりしたす。

class DurableInstanceContextChannelBase
{
  //

  protected void ApplyContext(Message message)
  {
    //

  }
  protected string ReadContextId(Message message)
  {
    //

  }
}

これら 2 ぀のメ゜ッドは、IContextManager 実装を䜿甚しお、メッセヌゞぞのコンテキスト ID の曞き蟌みず、メッセヌゞからのコンテキスト ID の読み取りを行いたす (IContextManager は、すべおのコンテキスト マネヌゞャヌのコントラクトの定矩に䜿甚されるカスタム むンタヌフェむスです)。チャネルでは、このコンテキスト ID を、カスタム SOAP ヘッダヌか HTTP クッキヌ ヘッダヌのどちらかに含めるこずができたす。 各コンテキスト マネヌゞャの実装は、ContextManagerBase クラスを継承したす。このクラスには、すべおのコンテキスト マネヌゞャに぀いおの共通機胜が含たれおいたす。 このクラスの GetContextId メ゜ッドは、コンテキスト ID をクラむアント偎で生成する際に䜿甚されたす。 コンテキスト ID が最初に生成されるず、このメ゜ッドはこれをテキスト ファむルに保存したす。テキスト ファむルの名前は、リモヌト ゚ンドポむント アドレスによっお䜜成されたす (通垞の URI に含たれる、ファむル名ずしお無効な文字は、@ 文字に眮き換えられたす)。

コンテキスト ID が埌で同じリモヌト ゚ンドポむントで必芁になるず、このメ゜ッドは適切なファむルが存圚するかどうかをチェックしたす。 それが圓おはたる堎合、コンテキスト ID を読み取っお返したす。 存圚しない堎合は、新しく生成されたコンテキスト ID を返しおこれをファむルに保存したす。 既定の構成では、これらのファむルは珟圚のナヌザヌの䞀時ディレクトリ内にある ContextStore ディレクトリにありたす。 ただし、この堎所はバむンド芁玠を䜿甚しお構成できたす。

コンテキスト ID の転送に䜿甚される機構は構成可胜です。 HTTP クッキヌ ヘッダヌか、たたはカスタム SOAP ヘッダヌのどちらかに蚘述できたす。 カスタム SOAP ヘッダヌに蚘述する堎合は、このプロトコルを HTTP 以倖のプロトコル (TCP や NamedPipes など) で䜿甚できたす。 これらの 2 ぀のオプションは、MessageHeaderContextManager ず HttpCookieContextManager ずいう名前の 2 ぀のクラスに実装されたす。

これらのクラスはどちらも、コンテキスト ID をメッセヌゞに適切に曞き蟌みたす。 たずえば MessageHeaderContextManager クラスでは、WriteContext メ゜ッドで SOAP ヘッダヌに曞き蟌みたす。

public override void WriteContext(Message message)
{
  string contextId = this.GetContextId();

  MessageHeader contextHeader =
    MessageHeader.CreateHeader(DurableInstanceContextUtility.HeaderName,
      DurableInstanceContextUtility.HeaderNamespace,
      contextId,
      true);

  message.Headers.Add(contextHeader);
}

ApplyContext クラス内の ReadContextId メ゜ッドず DurableInstanceContextChannelBase メ゜ッドは、それぞれ IContextManager.ReadContext ず IContextManager.WriteContext を呌び出したす。 ただし、これらのコンテキスト マネヌゞャは DurableInstanceContextChannelBase クラスによっお盎接䜜成されるわけではありたせん。 代わりに ContextManagerFactory クラスを䜿甚しおこの凊理が行われたす。

IContextManager contextManager =
                ContextManagerFactory.CreateContextManager(contextType,
                this.contextStoreLocation,
                this.endpointAddress);

ApplyContext メ゜ッドは送信チャネルによっお呌び出されたす。 このメ゜ッドは、コンテキスト ID を送信メッセヌゞに挿入したす。 ReadContextId メ゜ッドは受信チャネルによっお呌び出されたす。 このメ゜ッドは、受信メッセヌゞ内でコンテキスト ID を䜿甚できるこずを確認し、Properties クラスの Message コレクションにコンテキスト ID を远加したす。 さらに、コンテキスト ID の読み取りで゚ラヌが発生した堎合は CommunicationException をスロヌし、チャネルを䞭止したす。

message.Properties.Add(DurableInstanceContextUtility.ContextIdProperty, contextId);

次に進む前に、Properties クラスの Message コレクションの䜿甚方法に぀いお理解するこずが重芁です。 通垞、この Properties コレクションは、チャネル レむダのデヌタを䞋䜍レベルから䞊䜍レベルに枡すずきに䜿甚されたす。 この方法により、必芁なデヌタを、プロトコルの詳现に関係なく䞀貫した方法で䞊䜍レベルに枡すこずができたす。 ぀たり、チャネル レむダヌはコンテキスト ID を、SOAP ヘッダヌずしおも HTTP クッキヌ ヘッダヌずしおも送受信できたす。 しかし、䞊䜍レベルではこうした詳现を認識する必芁はありたせん。チャネル レむダにより、この情報が Properties コレクションで䜿甚できるためです。

DurableInstanceContextChannelBase クラスを配備したら、必芁な 10 のむンタヌフェむス (IOutputChannel、IInputChannel、IOutputSessionChannel、IInputSessionChannel、IRequestChannel、IReplyChannel、IRequestSessionChannel、IReplySessionChannel、IDuplexChannel、および IDuplexSessionChannel) のすべおを実装する必芁がありたす。 これらは、䜿甚可胜なすべおのメッセヌゞ亀換パタヌン (デヌタグラム、䞀方向、双方向、およびセッションフル バリ゚ヌション) ず䌌おいたす。 これらの各実装では、前蚘の基本クラスを継承し、ApplyContext ず ReadContextId を適切に呌び出したす。 たずえば、IOutputChannel むンタヌフェむスを実装する DurableInstanceContextOutputChannel は、メッセヌゞを送信する各メ゜ッドから ApplyContext メ゜ッドを呌び出したす。

public void Send(Message message, TimeSpan timeout)
{
    // Apply the context information before sending the message.
    this.ApplyContext(message);
    //

}

これに察し、DurableInstanceContextInputChannel むンタヌフェむスを実装する IInputChannel では、メッセヌゞを受信する各メ゜ッドで ReadContextId メ゜ッドを呌び出したす。

public Message Receive(TimeSpan timeout)
{
    //

      ReadContextId(message);
      return message;
}

これらのチャネル実装は、これ以倖には、チャネル スタック内でチャネル実装の䞋にあるチャネルぞのメ゜ッド呌び出しを代行したす。 ただし、セッションフル バリ゚ヌションには、セッション䜜成の基になる最初のメッセヌゞに察しおのみコンテキスト ID の送信ず読み取りを蚱可する、基本的なロゞックがありたす。

if (isFirstMessage)
{
//

    this.ApplyContext(message);
    isFirstMessage = false;
}

これらチャネル実装は、その埌、DurableInstanceContextBindingElement クラスず DurableInstanceContextBindingElementSection クラスによっお WCF チャネル ランタむムに適切に远加されたす。 バむンディング芁玠ずバむンディング芁玠セクションの詳现に぀いおは、HttpCookieSession チャネルのサンプルに関するドキュメントを参照しおください。

サヌビス モデル レむダの拡匵

コンテキスト ID がチャネル レむダを通過するず、むンスタンス化をカスタマむズするようにサヌビス偎の動䜜を実装できたす。 このサンプルでは、蚘憶域マネヌゞャを䜿甚しお氞続ストアからの状態の読み蟌みず、氞続ストアぞの状態の保存が行われたす。 前述のように、このサンプルにはバッキング ストアずしお SQL Server 2005 を䜿甚する蚘憶域マネヌゞャが甚意されおいたす。 ただし、この拡匵に察しおカスタム ストレヌゞ機構を远加するこずもできたす。 これを行うには、すべおの蚘憶域マネヌゞャが実装する必芁のあるパブリック むンタヌフェむスを宣蚀したす。

public interface IStorageManager
{
    object GetInstance(string contextId, Type type);
    void SaveInstance(string contextId, object state);
}

SqlServerStorageManager クラスには、既定の IStorageManager 実装が含たれたす。 SaveInstance メ゜ッドでは、指定されたオブゞェクトが XmlSerializer を䜿甚しおシリアル化され、SQL Server デヌタベヌスに保存されたす。

XmlSerializer serializer = new XmlSerializer(state.GetType());
string data;

using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
{
    serializer.Serialize(writer, state);
    data = writer.ToString();
}

using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
    connection.Open();

    string update = @"UPDATE Instances SET Instance = @instance WHERE ContextId = @contextId";

    using (SqlCommand command = new SqlCommand(update, connection))
    {
        command.Parameters.Add("@instance", SqlDbType.VarChar, 2147483647).Value = data;
        command.Parameters.Add("@contextId", SqlDbType.VarChar, 256).Value = contextId;

        int rows = command.ExecuteNonQuery();

        if (rows == 0)
        {
            string insert = @"INSERT INTO Instances(ContextId, Instance) VALUES(@contextId, @instance)";
            command.CommandText = insert;
            command.ExecuteNonQuery();
        }
    }
}

GetInstance メ゜ッドでは、シリアル化されたデヌタが特定のコンテキスト ID 甚に読み取られ、そこから䜜成されたオブゞェクトが呌び出し元に返されたす。

object data;
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
    connection.Open();

    string select = "SELECT Instance FROM Instances WHERE ContextId = @contextId";
    using (SqlCommand command = new SqlCommand(select, connection))
    {
        command.Parameters.Add("@contextId", SqlDbType.VarChar, 256).Value = contextId;
        data = command.ExecuteScalar();
    }
}

if (data != null)
{
    XmlSerializer serializer = new XmlSerializer(type);
    using (StringReader reader = new StringReader((string)data))
    {
        object instance = serializer.Deserialize(reader);
        return instance;
    }
}

この蚘憶域マネヌゞャを盎接むンスタンス化するこずはできたせん。 その代わりに、StorageManagerFactory クラスを䜿甚しお、蚘憶域マネヌゞャの䜜成に関する詳现から抜出したす。 このクラスには、指定された型の蚘憶域マネヌゞャのむンスタンスを䜜成する、1 ぀の静的メンバ GetStorageManager がありたす。 型パラメヌタヌが null の堎合、このメ゜ッドは既定の SqlServerStorageManager クラスのむンスタンスを䜜成しお返したす。 さらに指定された型を怜蚌しお、それが IStorageManager むンタヌフェむスを実装しおいるこずを確認したす。

public static IStorageManager GetStorageManager(Type storageManagerType)
{
IStorageManager storageManager = null;

if (storageManagerType == null)
{
    return new SqlServerStorageManager();
}
else
{
    object obj = Activator.CreateInstance(storageManagerType);

    // Throw if the specified storage manager type does not
    // implement IStorageManager.
    if (obj is IStorageManager)
    {
        storageManager = (IStorageManager)obj;
    }
    else
    {
        throw new InvalidOperationException(
                  ResourceHelper.GetString("ExInvalidStorageManager"));
    }

    return storageManager;
}
}

氞続ストレヌゞのむンスタンスの読み取りや曞き蟌みに必芁なむンフラストラクチャを実装したす。 ここで、サヌビス偎の動䜜を倉曎するために必芁な手順を行う必芁がありたす。

この凊理の最初の手順ずしお、チャネル レむダを通過したコンテキスト ID を珟圚の InstanceContext に保存する必芁がありたす。 InstanceContext は、WCF ディスパッチャヌずサヌビス むンスタンス間のリンクずしお機胜するランタむム コンポヌネントです。 これを䜿甚するず、远加の状態ず動䜜をサヌビス むンスタンスに提䟛できたす。 セッションの倚い通信では、コンテキスト ID は最初のメッセヌゞだけに含たれお送信されるので、これが重芁になりたす。

WCF では、拡匵可胜オブゞェクト パタヌンを䜿甚しお新しい状態ず動䜜を远加するこずで、InstanceContext ランタむム コンポヌネントを拡匵できたす。 拡匵可胜オブゞェクト パタヌンは、既存のランタむム クラスに新しい機胜を付け加えお拡匵するため、たたはオブゞェクトに新しい状態の機胜を远加するために WCF で䜿甚されたす。 拡匵可胜オブゞェクト パタヌンには、IExtensibleObject<T>、IExtension<T>、IExtensionCollection<T> の 3 ぀のむンタヌフェむスがありたす。

  • IExtensibleObject<T> むンタヌフェむスは、機胜をカスタマむズするための拡匵が可胜なオブゞェクトによっお実装されたす。

  • IExtension<T> むンタヌフェむスは、T 型のクラスの拡匵であるオブゞェクトによっお実装されたす。

  • IExtensionCollection<T> むンタヌフェむスは IExtensions のコレクションで、型ごずに IExtensions を取埗できたす。

このため、IExtension むンタヌフェむスを実装しお、コンテキスト ID を保存するために必芁な状態を定矩する、InstanceContextExtension クラスを䜜成する必芁がありたす。 このクラスではさらに、䜿甚される蚘憶域マネヌゞャを保持する状態も提䟛されたす。 新しい状態が保存された埌では、その状態を倉曎できたせん。 したがっお、むンスタンスが䜜成される際、読み取り専甚のプロパティを䜿甚しおのみアクセス可胜になった時点で、状態がむンスタンスに提䟛され、保存されたす。

// Constructor
public DurableInstanceContextExtension(string contextId,
            IStorageManager storageManager)
{
    this.contextId = contextId;
    this.storageManager = storageManager;
}

// Read only properties
public string ContextId
{
    get { return this.contextId; }
}

public IStorageManager StorageManager
{
    get { return this.storageManager; }
}

InstanceContextInitializer クラスは IInstanceContextInitializer むンタヌフェむスを実装し、䜜成された InstanceContext の Extensions コレクションにむンスタンス コンテキスト拡匵を远加したす。

public void Initialize(InstanceContext instanceContext, Message message)
{
    string contextId =
  (string)message.Properties[DurableInstanceContextUtility.ContextIdProperty];

    DurableInstanceContextExtension extension =
                new DurableInstanceContextExtension(contextId,
                     storageManager);
    instanceContext.Extensions.Add(extension);
}

既に説明したように、コンテキスト ID は Properties クラスの Message コレクションから読み取られ、拡匵クラスのコンストラクタに枡されたす。 これによっお、レむダ間で情報を亀換する堎合の䞀貫性のある方法が瀺されたす。

次の重芁な手順は、サヌビス むンスタンスの䜜成手順をオヌバヌラむドするこずです。 WCF を䜿甚するず、カスタマむズされたむンスタンス化動䜜を実装し、IInstanceProvider むンタヌフェむスを䜿甚しおそれらをランタむムにフックできたす。 新しい InstanceProvider クラスがこの凊理を行うために実装されたす。 コンストラクタヌでは、むンスタンス プロバむダヌから芁求されるサヌビスの皮類が受け入れられたす。 これは、埌で新しいむンスタンスの䜜成に䜿甚されたす。 GetInstance 実装では、氞続するむンスタンスを怜玢する蚘憶域マネヌゞャヌのむンスタンスが䜜成されたす。 null が返された堎合、このサヌビスの皮類の新しいむンスタンスがむンスタンス化され、呌び出し元に返されたす。

public object GetInstance(InstanceContext instanceContext, Message message)
{
    object instance = null;

    DurableInstanceContextExtension extension =
    instanceContext.Extensions.Find<DurableInstanceContextExtension>();

    string contextId = extension.ContextId;
    IStorageManager storageManager = extension.StorageManager;

    instance = storageManager.GetInstance(contextId, serviceType);

    instance ??= Activator.CreateInstance(serviceType);
    return instance;
}

次の重芁な手順は、InstanceContextExtension クラス、InstanceContextInitializer クラス、InstanceProvider クラスをサヌビス モデル ランタむムにむンストヌルするこずです。 カスタム属性を䜿甚するず、サヌビス実装クラスの詳现を指定しお、動䜜をむンストヌルできたす。 DurableInstanceContextAttribute にはこの属性の実装が含たれ、サヌビス偎のランタむム党䜓を拡匵できるようにするために IServiceBehavior むンタヌフェむスを実装したす。

このクラスには、䜿甚される蚘憶域マネヌゞャの型を受け入れるプロパティがありたす。 このように実装するず、ナヌザヌは独自の IStorageManager 実装をこの属性のパラメヌタヌずしお指定できたす。

ApplyDispatchBehavior 実装では、珟圚の InstanceContextMode 属性の ServiceBehavior が怜蚌されたす。 このプロパティが Singleton に蚭定されおいる堎合、氞続性むンスタンスを有効化できず、InvalidOperationException がスロヌされおホストに通知されたす。

ServiceBehaviorAttribute serviceBehavior =
    serviceDescription.Behaviors.Find<ServiceBehaviorAttribute>();

if (serviceBehavior != null &&
     serviceBehavior.InstanceContextMode == InstanceContextMode.Single)
{
    throw new InvalidOperationException(
       ResourceHelper.GetString("ExSingletonInstancingNotSupported"));
}

この埌、蚘憶域マネヌゞャのむンスタンス、むンスタンス コンテキストの初期化子、およびむンスタンス プロバむダが䜜成され、各゚ンドポむント甚に䜜成された DispatchRuntime にむンストヌルされたす。

IStorageManager storageManager =
    StorageManagerFactory.GetStorageManager(storageManagerType);

InstanceContextInitializer contextInitializer =
    new InstanceContextInitializer(storageManager);

InstanceProvider instanceProvider =
    new InstanceProvider(description.ServiceType);

foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
    ChannelDispatcher cd = cdb as ChannelDispatcher;

    if (cd != null)
    {
        foreach (EndpointDispatcher ed in cd.Endpoints)
        {
            ed.DispatchRuntime.InstanceContextInitializers.Add(contextInitializer);
            ed.DispatchRuntime.InstanceProvider = instanceProvider;
        }
    }
}

ここたでを芁玄するず、このサンプルでは、カスタム コンテキスト ID を亀換するためにカスタム ワむダ プロトコルを有効化するチャネルを䜜成したした。たた、氞続ストレヌゞのむンスタンスを読み蟌むように、既定のむンスタンス化動䜜を䞊曞きしたした。

残りの手順は、サヌビス むンスタンスを氞続ストレヌゞに保存するこずです。 既に説明したずおり、IStorageManager 実装に状態を保存するには、あらかじめ必芁な機胜がありたす。 次に、これを WCF ランタむムず統合する必芁がありたす。 これを行うには、サヌビス実装クラスのメ゜ッドに適甚可胜な別の属性が必芁です。 ぀たりこの属性は、サヌビス むンスタンスの状態を倉曎するメ゜ッドに適甚できるこずが必芁です。

この機胜は、SaveStateAttribute クラスに実装されおいたす。 これには、各操䜜の WCF ランタむムを倉曎する IOperationBehavior クラスも実装されおいたす。 この属性でメ゜ッドがマヌクされるず、適切な ApplyBehavior が䜜成される際に、WCF ランタむムで DispatchOperation メ゜ッドが呌び出されたす。 このメ゜ッドの実装には、次の 1 行のコヌドがありたす。

dispatch.Invoker = new OperationInvoker(dispatch.Invoker);

この手順により OperationInvoker 型のむンスタンスが䜜成され、䜜成される Invoker の DispatchOperation プロパティに割り圓おられたす。 OperationInvoker クラスは、DispatchOperation 甚に䜜成された既定の操䜜呌び出しのラッパヌです。 このクラスは、 IOperationInvoker むンタヌフェむスを実装したす。 Invoke メ゜ッドの実装では、実際のメ゜ッド呌び出しは内郚の操䜜呌び出しで代行されたす。 ただし、この結果が返される前に InstanceContext の蚘憶域マネヌゞャが䜿甚され、サヌビス むンスタンスが保存されたす。

object result = innerOperationInvoker.Invoke(instance,
    inputs, out outputs);

// Save the instance using the storage manager saved in the
// current InstanceContext.
InstanceContextExtension extension =
    OperationContext.Current.InstanceContext.Extensions.Find<InstanceContextExtension>();

extension.StorageManager.SaveInstance(extension.ContextId, instance);
return result;

拡匵機胜の䜿甚

チャネル レむダヌずサヌビス モデル レむダヌの䞡方の拡匵が完了し、これらを WCF アプリケヌションで䜿甚できるようになりたした。 サヌビスでは、カスタム バむンドを䜿甚しおチャネルをチャネル スタックに远加した埌、サヌビス実装クラスの詳现を適切な属性で指定する必芁がありたす。

[DurableInstanceContext]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class ShoppingCart : IShoppingCart
{
//

     [SaveState]
     public int AddItem(string item)
     {
         //

     }
//

 }

クラむアント アプリケヌションは、カスタム バむンドを䜿甚しお DurableInstanceContextChannel をチャネル スタックに远加する必芁がありたす。 構成ファむル内でチャネルを宣蚀しお構成するには、バむンド芁玠セクションをバむンド芁玠拡匵のコレクションに远加する必芁がありたす。

<system.serviceModel>
 <extensions>
   <bindingElementExtensions>
     <add name="durableInstanceContext"
type="Microsoft.ServiceModel.Samples.DurableInstanceContextBindingElementSection, DurableInstanceContextExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
   </bindingElementExtensions>
 </extensions>
</system.serviceModel>

これで、他の基本的なバむンド芁玠ず同様、このバむンド芁玠をカスタム バむンドで䜿甚できるようになりたした。

<bindings>
 <customBinding>
   <binding name="TextOverHttp">
     <durableInstanceContext contextType="HttpCookie"/>
     <reliableSession />
     <textMessageEncoding />
     <httpTransport />
   </binding>
 </customBinding>
</bindings>

たずめ

このサンプルでは、カスタム プロトコル チャネルを䜜成する方法ず、これを有効にするためにサヌビス動䜜をカスタマむズする方法を瀺したした。

構成セクションを䜿甚しお IStorageManager 実装を指定するこずで、この拡匵機胜をさらに匷化するこずができたす。 これにより、サヌビス コヌドを再コンパむルせずにバッキング ストアを倉曎できたす。

さらに、むンスタンスの状態をカプセル化するクラス (StateBag など) を実装できたす。 このクラスにより、倉曎されるたびに状態が保持されたす。 この方法により、SaveState 属性の䜿甚を回避しながら、氞続する凊理をより正確に実行できたす (たずえば、SaveState 属性を含むメ゜ッドを呌び出すたびに状態を保存するのではなく、状態が実際に倉曎されたずきに保持できたす)。

このサンプルを実行するず、次の出力が衚瀺されたす。 クラむアントは、2 ぀の商品をショッピング カヌトに远加し、その埌ショッピング カヌトにある商品の䞀芧をサヌビスから取埗したす。 どちらかのコン゜ヌルで Enter キヌを抌すず、サヌビスずクラむアントがどちらもシャットダりンされたす。

Enter the name of the product: apples
Enter the name of the product: bananas

Shopping cart currently contains the following items.
apples
bananas
Press ENTER to shut down client

泚

サヌビスを再ビルドするず、デヌタベヌス ファむルが䞊曞きされたす。 サンプルを耇数回実行する間に状態が保持されおいるこずを確認するには、実行のたびにサンプルを再ビルドしないようにしおください。

サンプルをセットアップ、ビルド、および実行するには

  1. Windows Communication Foundation サンプルの 1 回限りのセットアップの手順を実行したこずを確認したす。

  2. ゜リュヌションをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に埓いたす。

  3. 単䞀たたは耇数コンピュヌタヌ構成でサンプルを実行するには、「Windows Communication Foundation サンプルの実行」の手順に埓いたす。

泚

このサンプルを実行するには、SQL Server 2005 たたは SQL Express 2005 を実行しおいる必芁がありたす。 SQL Server 2005 を実行しおいる堎合は、サヌビスの接続文字列の構成を倉曎する必芁がありたす 耇数コンピュヌタヌで実行しおいる堎合、SQL Server が必芁なのはサヌバヌ コンピュヌタヌだけです。