8

与えられた:
- アプリケーション - デスクトップ GUI (WPF) .NET アプリ
- アプリケーションを監視する Windows サービス (.NET も)

Windows サービスは、アプリケーションが正常であることを確認するために定期的に「ping」を実行します (そうでない場合は、winservice がアプリケーションを再起動します)。
名前付きパイプを介して「ping」を実装するつもりでした。簡単にするために、WCF を使用することにしました。アプリケーションは、WCF サービスをホストします (1 つの操作 Ping が何かを返します)。Windows サービスは、この WCF サービスのクライアントであり、タイマーに基づいて定期的に呼び出します。

Windows 7
では以上です。Windows サービスは LocalService の下で実行されています (セッション #0)。
デスクトップ アプリケーションは、現在ログインしているユーザー (セッション #1) で実行されています。

問題:
Windows サービスは、デスクトップ アプリケーションで作成され、リッスンされている WCF エンドポイント (NetNamedPipeBinding を使用) を認識できません。つまり、wcf プロキシ経由の呼び出しで、「パイプ エンドポイント 'net.pipe://localhost/HeartBeat' がローカル マシンに見つかりませんでした」という例外が発生します。

別のデスクトップ アプリケーション (セッション #1) がエンドポイントを認識できるため、コードは問題ないと確信しています。

明らかに、ここでは、Win32 システム オブジェクトの分離のためのセキュリティ関連の事柄を扱っています。しかし、私が遭遇した制限を回避する方法があるはずです。
私は WCF のアプローチを犠牲にして、生の NamedPipe の方法に進むことができます。

4

2 に答える 2

7

より簡単な解決策は、WCF サービスをホストする Windows サービスで WCF デュプレックス コントラクトを使用することです。クライアントアプリは、起動時にサービスの操作を呼び出して自分自身を登録します。Ping は、クライアントのコールバック コントラクトでサービスによって定期的に呼び出される操作であり、アプリはこれに応答します。

Windows サービスは SeCreateGlobalPrivilege を使用して実行できるため、サービスの可視性はこのように機能します。そのため、サービスによってパイプ名が公開される共有メモリ オブジェクトをグローバル カーネル名前空間に作成して、他のセッションに表示できます。対話型アプリケーションは、Windows7 でその特権を簡単に取得できないため、そのようなアプリケーションの WCF サービスは、ローカル カーネル名前空間でパイプを公開するようにフォールバックし、独自のセッション内でのみ表示されます。

于 2010-11-29T20:03:57.250 に答える
6

最後に、System.IO.Pipes の名前付きパイプを直接使用して解決策を見つけました。WCF のパイプ サポートの実装は System.IO.Pipes を使用していないようです。

サーバー:

using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1))
{
    try
    {
        while (true)
        {
            // #1 Connect:
            try
            {
                pipeServer.WaitForConnection();
            }
            catch (ObjectDisposedException)
            {
                yield break;
            }
            if (ae.IsCanceled())
                return;

            // #2: Sending response:
            var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
            try
            {
                pipeServer.Write(response, 0, response.Length);
            }
            catch (ObjectDisposedException)
            {
                return;
            }

            // #3: Disconnect:
            pipeServer.Disconnect();
        }
    }
    finally
    {
        if (pipeServer.IsConnected)
            pipeServer.Disconnect();
    }
}

クライアント:

using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In))
{
    try
    {
        try
        {
            pipeClient.Connect(TIMEOUT);
        }
        catch(TimeoutException ex)
        {
            // nobody answers to us
            continue;
        }
        using (var sr = new StreamReader(pipeClient))
        {
            string temp;
            while ((temp = sr.ReadLine()) != null)
            {
                // got response
            }
        }
    }
    catch(Exception ex)
    {
        // pipe error
        throw;
    }
}
于 2010-11-29T16:01:35.483 に答える