ようこそ Go!Go! ASP.NET へ ログイン | 登録 | ヘルプ

寝ても覚めても.NET(?)

Visual Studio 2005 Team System、主にVisual Studio 2005 Team Foundation Serverを中心とした紹介やらTipsやらを日々つづっていく日記です。

WCFのクライアント側でCookieを共有する

自分が思いっきりどはまったので手順のメモとして。


まず、サーバー側に適当にサービスを作成しておきます。
ここでは、仮に「MyWcfService.svc」という名前でsvcファイルを作成して、サービスのエントリーポイントとしておきます。

次に、クライアントで、このサービスに対してサービス参照を追加します。
とりあえず、MyWcfService.svcファイルをブラウザで表示して、表示されたURL(例えば、http://localhost:10000/MyWcfService.svc)を
コピーってサービス参照の追加の画面でURLとして指定しましょう。

Client側のプロジェクトには、「ServiceReference1」なんてのが追加されてるはずなので、

ServiceReference1.MyWcfServiceClient client = new ServiceReference1.MyWcfServiceClient();
try
{
  client.Execute();
}
finally
{
  client.Close();
}

といった感じでアクセスできるはずです。
では、以下のコードで、ExecuteメソッドとPostExecuteメソッド間におけるクッキーの受け渡しを考えると・・・。

ServiceReference1.MyWcfServiceClient client1 = new ServiceReference1.MyWcfServiceClient();
try
{
  client1.Execute();
}
finally
{
  client1.Close();
}
ServiceReference1.MyWcfServiceClient client2 = new ServiceReference1.MyWcfServiceClient();
try
{
  client2.PostExecute();
}
finally
{
  client2.Close();
}

さて、どうやりましょう。
単純には、app.configファイルにあるWCFの構成設定を変更して、

<system.servicemodel>
  <bindings>
    <basichttpbinding>
      <binding allowcookies="true" name="NewBinding" />
    </basichttpbinding>
  </bindings>
  <client>
    <endpoint mywcfservice.svc?? localhost:10000 http: address=">
                    binding="basicHttpBinding" bindingConfiguration="NewBinding"
                    contract="ServiceReference1.MyWcfService"
                    name="BasicHttpBinding_MyWcfService" />
  </client>
</system.servicemodel>

としたいところです。
が、これだとNGです。

ServiceReference1.MyWcfServiceClientクラスを生成する場合、これは内部的にはChannelFactoryクラスが利用されていますが、
ChannelFactoryクラスのCookieのスコープはインスタンスごとに異なります。
このため、単純に構成ファイルにCookieを使うという宣言をしただけでは2つ目のサンプルコードでCookieを受け渡すことはできません。

そこで、さっきのサンプルを以下のように変更します。

CookieContainer container = new CookieContainer();
ServiceReference1.MyWcfServiceClient client1 = new ServiceReference1.MyWcfServiceClient();
try
{
  using (OperationContextScope scope = new OperationContextScope(client1.InnerChannel))
  {
    client1.Execute();

    //ブログの横幅の都合でいろいろ取得しながら書いてます。
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty httpResponse;
    httpResponse = properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;

    string cookie = httpResponse.Headers[HttpResponseHeader.SetCookie];
    container.SetCookies(new Uri(“http://dummy/”), cookie);
  }
}
finally
{
  client1.Close();
}
ServiceReference1.MyWcfServiceClient client2 = new ServiceReference1.MyWcfServiceClient();
try
{
  using (OperationContextScope scope = new OperationContextScope(client2.InnerChannel))
  {
    MessageProperties properties = OperationContext.Current.OutgoingMessageProperties;
    HttpRequestMessageProperty httpRequest;
    if (properties.ContainsKey(HttpRequestMessageProperty.Name))
    {
      httpRequest = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
    }
    if (httpRequest == null)
    {
      httpRequest = new HttpRequestMessageProperty();
      properties.Add(HttpRequestMessageProperty.Name, httpRequest);
    }
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, container.GetCookieHeader(new Uri(“http://dummy/”)));
    client2.PostExecute();
  }
}
finally
{
  client2.Close();
}

最後に、設定ファイルでallowCookies = “true”としている場合には、”false”に設定しなおします。
# trueにしているとWCFランタイム内で、Cookieの再設定が行われ、セットしていたものが無効になってしまうようです

これで、無事に完成です。
たとえば、認証処理とからめて利用するような場合には、重要ですね。

公開 28-05-2009 05:51 投稿者 libaty
タグ

コメント

コメントはありません
この投稿に対する新規コメントはできません
SkinName:iroha_Blog2
Powered by Community Server, by Telligent Systems