🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
WCF

WCFは、.NET Frameworkの提供する機能の一つ。サービス指向アプリケーション構築のためのフレームワークです。ネットワークを通して、異なるコンピュータ上で動くソフトウェア間の通信が可能になります。

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

6579閲覧

WCF通信 フォーム間のプロセス間通信について

tap_13

総合スコア15

WCF

WCFは、.NET Frameworkの提供する機能の一つ。サービス指向アプリケーション構築のためのフレームワークです。ネットワークを通して、異なるコンピュータ上で動くソフトウェア間の通信が可能になります。

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2019/10/20 07:29

編集2019/10/20 09:02

実行環境

VB/C#
WPF .Net Framework4.7.2

実現したいこと

プロセス間通信を行いフォームからフォームへ通信を行いたいです。

※イメージ
![イメージ説明

進捗状況

Form1,Form2の画面の表示(インスタンスの生成)は出来ています。

ソースコード

※フォーム1はC#、フォーム2はVBで開発しています。

①フォーム1のXAML

<Window x:Class="Form1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="450" Width="800"> <Grid> <TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="23" Margin="61,40,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/> <Button Content="Button" HorizontalAlignment="Left" Margin="238,40,0,0" VerticalAlignment="Top" Width="75" Height="23" Click="Button_Click"/> </Grid> </Window>

②フォーム1のコードビハインドクラス

namespace Form1 { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { private IWcfClient Host; public MainWindow() { Process.Start("Form2.exe"); Host = new ChannelFactory<IWcfClient>( new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), new EndpointAddress("net.pipe://localhost/Form2")).CreateChannel(); InitializeComponent(); } /// <summary> /// ボタン押下時のイベント /// </summary> private void Button_Click(object sender, RoutedEventArgs e) { try { var message = Host.CallExecute(TextBox1.Text); MessageBox.Show(message); } catch(FaultException<FailureInfo> fx) { FailureInfo info = fx.Detail; MessageBox.Show(info.Message); } } } }

③サービスのインタフェース

namespace Form1 { [ServiceContract] public interface IWcfClient { [OperationContract] [FaultContract(typeof(FailureInfo))] string CallExecute(string text); } }

④サービスの具象クラス

namespace Form1 { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class WcfClient: IWcfClient { public string CallExecute(string text) {        // WCF通信で発生する例外を追跡するためにthrow throw new FaultException<FailureInfo>(new FailureInfo(), "WCF通信エラー"); } } }

⑤デバッグ用(FaultExceptionでプロセス間通信の例外を見るために使用)

namespace Form1 { [DataContract] public class FailureInfo { [DataMember] public string Message { get; set; } } }

⑥フォーム2のコードビハインドクラス

''' <summary> ''' Form2のコードビハインド ''' </summary> Public Class MainWindow Public Host As ServiceHost Public Const Uri As String = "net.pipe://localhost/Form2" Public Sub New() Host = New ServiceHost(GetType(WcfClient)) Host.AddServiceEndpoint( GetType(IWcfClient), New NetNamedPipeBinding(NetNamedPipeSecurityMode.None), New Uri(Uri)) Host.Open() InitializeComponent() End Sub ''' <summary> ''' テキストボックスに値をセットする ''' </summary> Public Function Reply(ByVal text As String) As String      // テキストボックスにフォーム1より受け取った値をセット TextBox1.Text = text Return "Form2 Replyメソッドが呼ばれました" End Function End Class

試行内容

「④サービスの具象クラス」を以下のようにFacadeを用い、呼び出すアセンブリ・クラス・メソッドを動的に指定出来るように書き替え、Form1からForm2へプロセス間通信を実行しました。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class WcfClient: IWcfClient { public string CallExecute(string text) { // Facadeを用いてForm2のReplyメソッドをコール return Facade<string>("Form2.exe", "Form2.MainWindow", "Reply", text); } private T Facade<T>(string assembly, string className, string methodName, string text = "") { string path = Environment.CurrentDirectory + @"\" + assembly; Assembly asm = Assembly.LoadFrom(path); object obj = asm.CreateInstance(className); Type type = obj.GetType(); MethodInfo mi = type.GetMethod(methodName); object[] param = new object[1]; param[0] = text; object returnObj = mi.Invoke(obj, param); return (T)returnObj; } } }

上記を実行した結果、以下のスタックトレースが出力されました。

System.ServiceModel.FaultException HResult=0x80131501 Message=内部エラーのため、クライアントは要求を処理できませんでした。このエラーの詳細については、例外情報をクライアントに返信するためにサーバーで IncludeExceptionDetailInFaults を有効にするか (ServiceBehaviorAttribute または <serviceDebug> 構成動作を通じて)、Microsoft .NET Framework SDK ドキュメントに従ってトレースを有効にして、サーバーのトレース ログを調べてください。 Source=mscorlib スタック トレース: 場所 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 場所 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 場所 Form1.IWcfClient.CallExecute(String text) 場所 Form1.MainWindow.Button_Click(Object sender, RoutedEventArgs e) (C:\workspace\20191020\WcfConnection\Form1\MainWindow.xaml.cs):行 34 場所 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 場所 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 場所 System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) 場所 System.Windows.UIElement.RaiseEvent(RoutedEventArgs e) 場所 System.Windows.Controls.Primitives.ButtonBase.OnClick() 場所 System.Windows.Controls.Button.OnClick() 場所 System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e) 場所 System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e) 場所 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) 場所 System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) 場所 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 場所 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 場所 System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent) 場所 System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e) 場所 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) 場所 System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) 場所 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 場所 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 場所 System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) 場所 System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) 場所 System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) 場所 System.Windows.Input.InputManager.ProcessStagingArea() 場所 System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) 場所 System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) 場所 System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel) 場所 System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 場所 System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 場所 MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 場所 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) 場所 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) 場所 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) 場所 System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) 場所 MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) 場所 MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) 場所 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) 場所 System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) 場所 System.Windows.Application.RunDispatcher(Object ignore) 場所 System.Windows.Application.RunInternal(Window window) 場所 System.Windows.Application.Run(Window window) 場所 System.Windows.Application.Run() 場所 Form1.App.Main()

調べたところ、FaultExceptionの実行例外の詳細をクライアント側で取得するためには⑤のようなデバッグ追跡用のデータクラスが必要であったため、「FailureInfoクラス」を新規作成しました。
そしてプロセス間通信の実行例外(FaultException)のスタックトレースを確認するため「④サービスの具象クラス」のように書き換えました。

質問内容

「④サービスの具象クラス」でFaultExceptionをスローし、プロセス間通信の実行例外のスタックトレースを確認した結果、以下が出力されました。
自身で調査しましたが、真因が追求出来ていません。解決策をご存知の方いらっしゃいましたらご教授お願い致します。

場所 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 場所 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 場所 Form1.IWcfClient.CallExecute(String text) 場所 Form1.MainWindow.Button_Click(Object sender, RoutedEventArgs e) (C:\workspace\20191020\WcfConnection\Form1\MainWindow.xaml.cs):行 34

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/10/20 08:11

ご質問の意図が分からないのですが、Form1のButton_Click内で Host.CallExecute(TextBox1.Text)を呼び出していますが、 そのCallExecuteの実行内容は、ただ throw new FaultException<FailureInfo>(new FailureInfo(), "WCF通信エラー"); とFaultExceptionをthrowしているだけなので、 スタックトレースが報告されるのは当然だと思うのですが、そう言う話ではなくて??でしょうか。スタックトレース中の内容に不明な点があるということですか?
tap_13

2019/10/20 09:08 編集

回答ありがとうございます。試行内容を追記させていただきました。 >そのCallExecuteの実行内容は、ただ throw new FaultException<FailureInfo>(new FailureInfo(), >"WCF通信エラー"); とFaultExceptionをthrowしているだけなので、 >スタックトレースが報告されるのは当然だと思うのですが、そう言う話ではなくて??でしょうか。スタックトレース中の >内容に不明な点があるということですか? はい、後者でスタックトレースに不明点があります。 試行内容に追記させていただきましたが、CallExecuteでプロセス間通信を行うとスタックトレースの詳細が見れません。そのため、CallExecute内であえてthrow new FaultException<FailureInfo>(new FailureInfo(), "WCF通信エラー"); を行い、FaultExceptionのスタックトレースをクライアント側で見れるようにしていました。
guest

回答2

0

ベストアンサー

Facade メソッドでForm2の MainWindow インスタンスを生成していますが、
そのときには、すでにServiceHostが開始されているので二回目の起動となり名前付きパイプの作成に失敗します。

手元の環境にVB.NETがないのでC#で同等のコードを提示します。

csharp

1 public partial class MainWindow : Window 2 { 3 static ServiceHost Host; 4 const string Uri = "net.pipe://localhost/Form2"; 5 6 public MainWindow() 7 { 8 if (Host == null) 9 { 10 Host = new ServiceHost(typeof(WcfClient)); 11 12 Host.AddServiceEndpoint( 13 typeof(IWcfClient) 14 , new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), 15 new Uri(Uri)); 16 Host.Open(); 17 } 18 InitializeComponent(); 19 } 20 21 public string Reply(string text) 22 { 23 TextBox1.Text = text; 24 return "Form2 Replyメソッドが呼ばれました"; 25 } 26 } 27

このように ServiceHost の開始を一回だけにすれば、呼び出しできるようになります。
ただし、このコードはよくない設計になってしまっているため ServiceHost の初期化処理を MainWindow クラスから分離できないか検討したほうがよいでしょう。

投稿2019/10/31 06:13

編集2019/10/31 06:27
yuto_club

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tap_13

2019/11/03 14:36

回答ありがとうございます、解決いたしました。 ServiceHostの初期化処理を2回行っていることが原因でした。
tap_13

2019/11/03 14:37

回答ありがとうございます、解決いたしました。 ServiceHostの初期化処理を2回行っていることが原因でした。
guest

0

回答ありがとうございます、解決いたしました。
ServiceHostの初期化処理を2回行っていることが原因でした。

投稿2019/11/03 14:36

tap_13

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問