いまさらWCFでプロセス間通信

.NET Framework3.0で登場したWCF。

「プロセス間通信」というと、名前付きパイプ、メールスロット、ファイルマッピング、.NET2.0で登場した.NET Remoting。

私自身WCFの全貌を理解しているとは言えませんが、WCFを使ったプロセス間通信を紹介します。

大まかな手順は、

  1. サービス内容を決定する
  2. サービスを提供する側を実装する
  3. サービスを受ける側を実装する

となります。

作成予定のプロジェクトは以下の3つ。

WCFプロジェクト構成

Step1.サービス内容(=コントラクト)を決定する

どのようなサービスを提供・受領するか、サービス内容(Contract : コントラクト)を決定します。

WCFではABCという言葉が出てきますが、AはAddress(どこから)、BはBinding(どうやって)、CはContract(なにを)を表しており、ここではこの’ C ‘ に相当するものを用意します。といっても簡単で、C#のInterfaceで実装するだけです。

TestContract.proj

Interface 1つをもつクラスライブラリとして作成します。

using System;
using System.ServiceModel;

namespace TestContract
{
    [ServiceContract]
    public interface ITestContract
    {
        [OperationContract]
        DateTime GetTime();
    }
}

これだけ。時間を渡すという「約束(Contract)」をはっきりさせておきます。
※後で出てくる2つ含め3つ全てのプロジェクトでSystem.ServiceModelアセンブリおよびSystem.ServiceModel名前空間の参照が必要です。

Step2.サービスを提供する側(Server, Host, Service Provider)を実装する

WCFでは通常Hostというようです、今回はコンソールアプリとして作成します。

TestServer.proj内 TestServer.cs

using System;
using System.ServiceModel;

namespace TestServer
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class TestServer : TestContract.ITestContract
    {
        public DateTime GetTime()
        {
            return DateTime.Now;
        }
    }
}

現在時刻をもらいます。InstanceContextModeはMSDNに記載の以下の目的で設定しています。

instancemodeの必要性
program.cs

using System;
using System.ServiceModel;

namespace TestServer
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(new TestServer(),
                new Uri("net.pipe://localhost"));
            host.AddServiceEndpoint(
                typeof(TestContract.ITestContract),
                new NetNamedPipeBinding(),
                "InterProcessCommunication");
            host.Open();
            Console.WriteLine("Enter押下で終了.");
            Console.ReadLine();
        }
    }
}

Step3.サービスを受ける側(Client, Service User)を実装する
ごくシンプルなWindowsFormsで作成します。

formの図

ClientForm.cs

using System;
using System.Windows.Forms;
using System.ServiceModel;

namespace TestClient
{
    public partial class ClientForm : Form
    {
        private readonly TestContract.ITestContract server;
        public ClientForm()
        {
            InitializeComponent();
            server = new ChannelFactory<TestContract.ITestContract>(
                new NetNamedPipeBinding(),
                new EndpointAddress("net.pipe://localhost/InterProcessCommunication")
                ).CreateChannel();
            updateTimer.Enabled = true;
        }

        private void updateTimer_Tick(object sender, EventArgs e)
        {
            if (server == null) {
                return;
            }
            try{
                labelTime.Text = server.GetTime().ToString();
            }
            catch (EndpointNotFoundException){
                labelTime.Text = string.Empty;
            }
            catch (CommunicationException){
                labelTime.Text = string.Empty;
            }
        }
    }
}

EndPointAddressでServerを作成するときに使ったアドレスと合致させる必要がある点に注意してください。

これにて終了です。

サーバ不在時はEndPointNotFoundException、通信中に途切れた場合はCommunicationExceptionが発生します。
どちらもFormでcatchして表示をなくしています。
動作様子-サーバ不在

この状態からサーバを立ち上げると・・
動作様子-通信できているとき
現在時間表示がされるようになります。

接続確立状態からサーバが死んだとしても、クライアント側は例外のケアさえしておけば再接続のような処理は不要で、
サーバが立ち上がったときに再度自動的に接続が可能となります。

広告