WCF では、クライアントがサービスを呼び出すとき、チャネルを開閉するコードを書く必要があります。サービスを呼び出す度に同じコードを書くのは面倒です。
この問題を解決する方法として、以前、RealProxy を使って動的に WCF クライアントを生成するサンプルを紹介しました。
しかし、コードブロックを上手く利用すれば、わざわざ RealProxy を使う必要はないかもしれません。
例えば、次のようなクラスを用意します。
public class ChannelProvider<TChannel> where TChannel : class { private Binding _binding; private string _endpointAddress; public ChannelProvider(Binding binding, string address) { _binding = binding; _endpointAddress = address; } // Channel を生成 public TChannel CreateChannel() { return ChannelFactory<TChannel> .CreateChannel(_binding, new EndpointAddress(_endpointAddress)); } // 結果を返さないメソッドを呼び出す public void Invoke(Action<TChannel> block) { TChannel channel = CreateChannel(); block(channel); ((IChannel)channel).Close(); } // 結果を返すメソッドを呼び出す public TResult Result<TResult>(Func<TChannel, TResult> block) { TChannel channel = CreateChannel(); TResult result = block(channel); ((IChannel)channel).Close(); return result; } }
このクラスを使って、次のようにサービスを呼び出します。
[ServiceContract] public interface IGreetingService { [OperationContract] string Greet(string name); } public class GreetingService : IGreetingService { public string Greet(string name) { return string.Format("Hello, {0}!", name); } } class Program { static void Main(string[] args) { // サービス開始 string address = "net.pipe://localhost/Greeting"; ServiceHost host = new ServiceHost(typeof(GreetingService)); host.AddServiceEndpoint(typeof(IGreetingService), new NetNamedPipeBinding(), address); host.Open(); ChannelProvider<IGreetingService> provider = new ChannelProvider<IGreetingService>( new NetNamedPipeBinding(), address); // チャネルを使って処理を行うブロックを、Result メソッドの引数に渡す string result = provider.Result<string>(p => p.Greet("Ichiro")); Console.WriteLine(result); Console.ReadLine(); // サービス終了 host.Close(); } }
コードブロックを渡すので、チャネルを開いてから閉じる間に、複数回サービスを呼び出せます。それに対し、RealProxy を使った方法だと、サービスを呼び出す度にチャネルを開閉します。
RealProxy を使った方法よりも、今回の方法のほうが効率がいいですね。