WPF アプリケーションに WCF サービスをホストさせます
App.xaml
<Application x:Class="WcfHostSample.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </Application>
App.xaml.cs
using System.ServiceModel; using System.Windows; namespace WcfHostSample { public partial class App : Application { public const string address = "net.pipe://localhost/Greeting"; private ServiceHost host = null; protected override void OnStartup(StartupEventArgs e) { host = new ServiceHost(typeof(GreetingService)); host.AddServiceEndpoint(typeof(IGreetingService), new NetNamedPipeBinding(), address); host.Open(); MainWindow = new Window1(); MainWindow.Show(); base.OnStartup(e); } protected override void OnExit(ExitEventArgs e) { if (host != null) { host.Close(); } base.OnExit(e); } } [ServiceContract] public interface IGreetingService { [OperationContract] string Greet(string name); } public class GreetingService : IGreetingService { public string Greet(string name) { return string.Format("Hello, {0}!", name); } } }
WCF サービスはあいさつ文を返す簡単なもの。WPF メインウィンドウを表示する前に、App クラス内で WCF サービスを起動しています。
自分でホストした WCF サービスを呼び出してみます
Window1.xaml
<Window x:Class="WcfHostSample.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <Label Content="名前:"/> <TextBox x:Name="_nameTextBox"/> <Label Content="結果"/> <TextBox x:Name="_resultTextBox" IsReadOnly="True"/> <Button Content="あいさつする!" Click="Button_Click"/> </StackPanel> </Window>
Window1.xaml.cs
using System; using System.ServiceModel; using System.Threading; using System.Windows; namespace WcfHostSample { /// <summary> /// Window1.xaml の相互作用ロジック /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { string name = _nameTextBox.Text; if (string.IsNullOrEmpty(name)) { MessageBox.Show("名前を入力して下さい。"); return; } // UI スレッドで実行すると固まる。なぜ? //IGreetingService proxy = ChannelFactory<IGreetingService>.CreateChannel( // new NetNamedPipeBinding(), // new EndpointAddress(App.address)); //_resultTextBox.Text = proxy.Greet(name); //((IClientChannel)proxy).Close(); // 別スレッドで実行すると上手くいく Thread thread = new Thread((ThreadStart)delegate { IGreetingService proxy = ChannelFactory<IGreetingService>.CreateChannel( new NetNamedPipeBinding(), new EndpointAddress(App.address)); string result = proxy.Greet(name); Dispatcher.BeginInvoke(new Action(() => { _resultTextBox.Text = result; })); ((IClientChannel)proxy).Close(); }); thread.Start(); } } }
Button がクリックされたら、WCF サービスを呼び出しています。
WCF サービス呼び出しでハマった
上記サンプルコード内にコメントで書いていますが、UI スレッド上で WCF サービスを呼び出すと、Greet メソッドのところで固まってしまいました。そして TimeoutException 発生。
試しに、別スレッドで WCF サービスを呼び出してみると、固まることなく WCF サービスから結果を取得できました。
ホストとクライアントが別 exe だと、UI スレッドで呼び出しても上手くいくので、両方を1つの WPF で兼ねているのが問題なんだろう。でも、詳しい原因がわからない……。ネットで調べても、こんな事をやる人はいないみたい。
もう少し調べてみます
でも、そろそろタイムリミットかも。UI スレッドとは違うスレッドで WCF サービスを呼び出して回避できることは分かったけれど、原因が分らないままだと気持ち悪い。