WCF で簡単にプロセス間通信

開発部の y-okubo です。

今回は C# の(正確には .NET Framework)WCF を使ってプロセス間通信を簡単に行ってみようと思います。

WCF の基本的な概念については以下の記事を参照してください。

www.atmarkit.co.jp

今回やりたい事を図にすると以下のような内容になります。

f:id:nekojarashi-Inc:20170814181814p:plain

WCF 関係コード

サービス実装

お行儀良くやるのであれば、インターフェイスの定義と実装は別ファイルにすべきでしょうが、ここはサクッと作ってしまいたいので単一ファイルに両方定義してしまいます。

using System.ServiceModel;

namespace Hoge
{
    [ServiceContract]
    public interface ISearchService
    {
        [OperationContract]
        void Execute();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
    public class SearchService : ISearchService
    {
        public delegate void Searcher();

        public Searcher SercherDelegate;

        public void Execute()
        {
            SercherDelegate();    // 実装はデリゲートします
        }
    }
}

サービス起動(サーバ)

例外処理はかなりアバウトです。

SearchService service = new SearchService();
service.SercherDelegate = hogeForm.SearchRequest;    // デリゲート登録

serviceHost = new ServiceHost(
    service,
    new Uri("net.pipe://localhost/Hoge"));

try
{
    serviceHost.AddServiceEndpoint(
        typeof(ISearchService),
        new NetNamedPipeBinding(),
        "SearchService");
    serviceHost.Open();
}
catch (AddressAlreadyInUseException)
{
    MessageBox.Show("既にサービスは起動しています。");
}
catch (Exception e)
{
    MessageBox.Show(e.ToString());
}

サービス呼び出し(クライアント)

new ChannelFactory<ISearchService>(
    new NetNamedPipeBinding(),
    new EndpointAddress("net.pipe://localhost/Hoge/SearchService")).CreateChannel()
    .Execute();

サービス関連のハマり所

  • NetNamedPipeBinding() の引数はサービス側と呼び出し側で揃えないと例外が発生するので気を付ける。
  • EndpointAddress の指定を間違えないように気を付ける。
    • EndpointAddress は ServiceHost の URI と Endpoint を結合した文字列。
    • サービス側はこれらを別々に指定しているが、呼び出し側は結合した文字列を指定しているので注意。

Windows Forms 関係コード

実際にフォームを呼び出す

サービス起動時に登録したデリゲートメソッドです。

public void SearchRequest()
{
    // ここは必ず別スレッドで呼ばれる
    Invoke((MethodInvoker)delegate ()
    {
        MainForm_ShowSearchForm(this, null);
    });
}

フォーム呼び出し時のハマり所

  • メインスレッドで実行せねばならないので気を付ける。
    • 上記のメソッドはサービスのスレッド(バックグラウンド)から呼び出されることが分かっているので、InvokeRequired でのチェックを省略しています。

まとめ

WCF を使う方法について簡単に紹介いたしました。

プロセス間通信となるとかなり面倒なイメージがありますが、WCF を使えばサーバ・クライアント通信の様に行うことができます。

最近のアプリは役割毎に小さな粒度でプロセスを分けて緩やかに連携する、いわゆるマイクロサービス的な構成の物が増えているようですので、C# のみでアプリを構成するのであれば WCF は有力な選択肢になるかと思います。

WCF を使う上でこの記事がお役に立てば幸いです。

ねこじゃらしについて

ねこじゃらしでは C# に限らず Ruby (Ruby on Rails) や JavaScript での開発経験がある Web エンジニア、UI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com