WCF”ビヘイビア”なるもの

WPFでのビヘイビアとは、Viewに関連する振る舞い(Behavior)を再利用可能な形で作成したものでした。WCFにもビヘイビアというものがありWCFでのビヘイビアとは、WCFでの通信時の特定のタイミングで何らかの振る舞い(Behavior)を発動させるためのものです。

WPFのビヘイビアはコミュニティの間で「そう呼ばれているもの」 (それがBlendで採用され公にはなっている)ですが、WCFのビヘイビアはそういうクラスがあり「もともと正式なもの」という違いがあります。

 

1.WCFビヘイビアの種類

WCFのビヘイビアとは大きく下記4種あるようです。

①サービスビヘイビア(IServiceBehaviorを実装する)
サーバ側に追加する機能追加モジュールのこと。WSDLファイルによりサーバが提供する機能を公開することができるが、サービスビヘイビアの一種であるserviceMetadataビヘイビアを使うとこのWSDLファイル作成を自動作成&公開できる。(このWSDLファイルを公開するエンドポイントがMEXエンドポイントであり、これがあるとユーザは簡単にプロキシクラスや構成ファイルが作成できるようになる)

②エンドポイントビヘイビア(IEndpointBehaviorを実装する)
サービスビヘイビアがサーバ側に対するビヘイビアだったのに対し、エンドポイントビヘイビアはエンドポイント単位のビヘイビアです。ただし良い実例を見かけません;

③コントラクトビヘイビア(IContractBehaviorを実装する)
コントラクト単位でのビヘイビアです、こちらも良い実例を見かけません;

④操作ビヘイビア(IOperationBehaviorを実装する)
Interfaceとして定義するWCFサービスにはOperationContract属性をつけます。このInterfaceのメソッドに特性を追加するのが操作ビヘイビアです。代表例として、トランザクション操作を実装する操作ビヘイビアがあります(OperationBehaviorにTransactionScopeRequired=trueとして指定)。

これらのスコープや、構成方法についてはこちらを参照ください。

 

2.WCFビヘイビアの利用

上記①に記載したMEXエンドポイントの公開方法を見ておきます。迷子にならないようにまず全体のプロジェクト・ファイル構成を見ておきます(下図)。いずれもコンソールアプリです。

project
サービスを公開するためサーバー側から作成します。まずはコントラクトから。

コントラクトとしての、ISampleService.cs

namespace WcfBehavior.TestServer
{
    using System.ServiceModel;
    [ServiceContract]
    interface ISampleService
    {
        [OperationContract]
        string Get();
    }
}

これを実際に実装する、TestService.cs

namespace WcfBehavior.TestServer
{
    using System;

    class TestService : ISampleService
    {
        public string Get()
        {
            return DateTime.Now.ToString();
        }
    }
}

App.Config<without MEX>

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.serviceModel>
    <services>
      <service name="WcfBehavior.TestServer.TestService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/WcfBehavior"/>
          </baseAddresses>
        </host>
        <endpoint address ="WcfBehaviorTest"
                  binding="basicHttpBinding"
                  contract="WcfBehavior.TestServer.ISampleService"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

これにMEXを追加した、App.config<with MEX>

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.serviceModel>
    <services>
      <service name="WcfBehavior.TestServer.TestService"
               behaviorConfiguration ="SampleMexBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/WcfBehavior"/>
          </baseAddresses>
        </host>
        <endpoint address ="WcfBehaviorTest"
                  binding="basicHttpBinding"
                  contract="WcfBehavior.TestServer.ISampleService"/>
        <endpoint address="WcfBehaviormex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SampleMexBehavior">
          <serviceMetadata httpGetEnabled="True"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

MEXはWSDLを送信するエンドポイントなのでエンドポイントとして定義が必要です。また公開されるISampleServiceはWSDLをHttp経由で取得できるようにする、というビヘイビアを設定しています(上記、behaviorConfiguration)。最後にサーバ側メイン処理。

 Program.cs(サーバー側)

namespace WcfBehavior.TestServer
{
    using System;
    using System.ServiceModel;
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(TestService));
            host.Open();
            Console.WriteLine("Press Enter to Exit.");
            Console.ReadLine();
        }
    }
}

このサーバーConsoleアプリを管理者として実行した状態で、クライアント側作成に移ります。

クライアント側ではサーバで公開したMEXエンドポイントを利用します。まず、プロジェクトを右クリックして、[追加] – [サービスの追加] を開き、アドレスを指定して [移動] を押すと

add_service

このようにサービスが見つかります。サービスが見つからない場合、

  • サーバーが起動状態か?
  • MEXエンドポイントが公開されているか?

を確認ください。名前空間は今回このままServiceReference1としておきますが、これでOkを押すとApp.configが自動的に更新され、プロキシクラスも作成されます(ぱっと見見えません)。これの使い方は非常に簡単!

Program.cs(クライアント側)

namespace WcfBehavior.TestClient
{
    using System;
    class Program
    {
        static void Main(string[] args)
        {
            var proxy = new ServiceReference1.SampleServiceClient();
            Console.WriteLine(proxy.Get());
            Console.WriteLine("Press Enter to Exit.");
            Console.ReadLine();
        }
    }
}

サービス名+Clientがプロキシクラスの名前になるようです。

MEXの説明がメインになりましたが、WCFビヘイビアを使うことで他にも、同時実行数や同時呼び出し数を制限したり,セキュリティを設けたり,通信時のログをとったり、といった目的で使えます。

 

3.ビヘイビアの自作

MSDNに詳しく記載があります。どのビヘイビアを作るか?によってInterfaceが決まりますが、今回は何もしないサービスビヘイビアを作ってみます。サーバ側に下記2ファイルを追加します。

CustomBehavior.cs

namespace WcfBehavior.TestServer
{
    using System;
    using System.Collections.ObjectModel;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Channels;

    public class CustomBehavior : IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase, 
            Collection<ServiceEndpoint> endpoints, 
            BindingParameterCollection bindingParameters)
        {
            Console.WriteLine("AddBindingParameters has called");
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase)
        {
            Console.WriteLine("CustomBehavior has applied.");
        }

        public void Validate(ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase)
        {
            Console.WriteLine("Validate has called.");
        }
    }
}

このビヘイビアを構成ファイルから使えるようにするためにもう一つ、下記クラスが必要となります。

CustomBehaviorElement.cs

namespace WcfBehavior.TestServer
{
    using System;
    using System.ServiceModel.Configuration;
    public class CustomBehaviorElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(CustomBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new CustomBehavior();
        }
    }
}

このクラスを作る場合、System.Configurationへの参照が必要になります。これを構成ファイルから使うようにするにはサーバー側のApp.configを以下のように変更します。

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.serviceModel>
    <services>
      <service name="WcfBehavior.TestServer.TestService"
               behaviorConfiguration ="SampleMexBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/WcfBehavior"/>
          </baseAddresses>
        </host>
        <endpoint address ="WcfBehaviorTest"
                  binding="basicHttpBinding"
                  contract="WcfBehavior.TestServer.ISampleService"/>
        <endpoint address="WcfBehaviormex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SampleMexBehavior">
          <serviceMetadata httpGetEnabled="True"/>
          <customBehavior/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="customBehavior"
             type="WcfBehavior.TestServer.CustomBehaviorElement, WcfBehavior.TestServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
  </system.serviceModel>
</configuration>

カスタムビヘイビアの場合、extensionsタグを作って、その中にクラスとビヘイビア名を追加しておく必要があります。こうすることで少し上のserviceBehaviorsでカスタムビヘイビアを参照できるようになります。これは一番上でサービスのbehaviorConfigurationとして指定されているのでサービスへと適用される訳です。

最後になりましたが、これを動かしたのは以下。

activate_custombehavior

サーバ側でConsoleへの出力が確認できると思います(これはクライアントを起動させずにサーバ側起動直後に全文出力されます)。