別プロセスにコマンドライン引数を貯める

# 別プロセスにコマンドライン引数を貯める

## 前提
### 目的
以下の場合を想定して作成した。

* コマンドライン引数を用いて、アプリケーションを操作したい
* アプリケーションは多重起動させたくない
* アプリケーションはコマンドラインアプリケーションとして提供。
* でも複数起動されたときの引数は保持したい (今回はココ)

### 方法
WindowsFormsApplicationBaseやSocketを使って実装する手段もあったが、
今回は簡単にアプリケーション間通信が実装できるWCFを使った。

そのため、引数を投げるクライアントと受け取り、処理するサーバに分けて実装した。

## 手順
参考にも記載しているが、ほぼ [Part 2. Hello World WCF サーバの開発](https://blogs.msdn.microsoft.com/nakama/2008/09/25/part-2-hello-world-wcf/) と [Part 3. Hello World WCF クライアントの開発](https://blogs.msdn.microsoft.com/nakama/2008/10/01/part-3-hello-world-wcf/) の丸写しなので読める人はそっちを見たほうがよいと思う。

### 1. サーバー側
[Part 2. Hello World WCF サーバの開発](https://blogs.msdn.microsoft.com/nakama/2008/09/25/part-2-hello-world-wcf/)を参考に実装

1. 下記のコードをビルドする。

```CSharp:Program.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace Sample.Server
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(WcfService)))
            {
                host.AddServiceEndpoint(typeof(WcfService), new NetTcpBinding(),
                    "net.tcp://localhost:28661/Sample.Server/WcfService");

                // メタデータ取得用のエンドポイント。
                // 手順2のサービス参照の追加で必要。
                // 処理を実行するために管理者権限が必要となる。
                // サーバー処理としては無くても動く。
                host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
                host.Description.Behaviors.Remove(typeof(ServiceMetadataBehavior));
                host.Description.Behaviors.Add(new ServiceMetadataBehavior {
                    HttpGetEnabled = true,
                    HttpGetUrl = new Uri("http://localhost:8000/Sample.Server/WcfService/mex")
                });

                host.Open();
                Console.WriteLine("WCF サーバを起動しました。");

                // 終了待機用の入力待ち
                Console.ReadLine();
                host.Close();
            }
        }
    }
}
```


```CSharp:WcfService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
 
namespace Sample.Server
{
    // クライアント側から呼び出せる部分
    [ServiceContract]
    public class WcfService
    {
        static List<String[]> args_list = new List<String[]>();

        [OperationContract]
        public string GetMessage(string[] args)
        {
            args_list.Add(args);

            var result = string.Empty;
            foreach(string[]  args_for_res in args_list)
            {
                result = result + "\n" + String.Join(" ", args_for_res);
            }
            
            return result;
        }
    }
}

```

### 2. クライアント側
[Part 3. Hello World WCF クライアントの開発](https://blogs.msdn.microsoft.com/nakama/2008/10/01/part-3-hello-world-wcf/)を参考に実装

1. クライアント側のプロジェクトを作成する。
2. サーバー側を**管理者権限**で起動して待機させる。 (メタデータの公開周りで権限が必要？)
1. プロジェクトの[参照]を右クリックし [サービス参照の追加] を開く。
2. http://localhost:8000/Sample.Server/WcfService/mex を [アドレス] に入れて [OK] する。
3. Connected Services > ServiceReference1 が追加される。
2. 下記のコードからビルド。
1. クライアント側に引数を渡して実行すると、クライアント側でサーバに保存された引数が表示される。

```CSharp:Program.cs
using System;
 
namespace Sample.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceReference1.WcfServiceClient proxy = new ServiceReference1.WcfServiceClient();
            string ret = proxy.GetMessage(args);
            proxy.Close();

            Console.WriteLine(ret);
        }
    }
}
```

## 参考
[Part 1. WCF に導入されている新たな設計概念 – とあるコンサルタントのつぶやき](https://blogs.msdn.microsoft.com/nakama/2008/09/18/part-1-wcf/)
[Part 2. Hello World WCF サーバの開発 – とあるコンサルタントのつぶやき](https://blogs.msdn.microsoft.com/nakama/2008/09/25/part-2-hello-world-wcf/)
[Part 3. Hello World WCF クライアントの開発 – とあるコンサルタントのつぶやき](https://blogs.msdn.microsoft.com/nakama/2008/10/01/part-3-hello-world-wcf/)

## 備考
[C#|二重起動を禁止してコマンドライン引数を取得する | 貧脚レーサーのサボり日記](https://anis774.net/codevault/singleinstanceargs.html)

WindowsFormsApplicationBase を用いて実現する方法。

今回はコマンドラインアプリケーションだったため使わなかったが、
UI付きであればこちらのが楽だろう。