WCF で クライアント Channel を Close() するとき、非常に稀ですが、ネットワークエラーによって例外が発生する場合があります。
もし例外が発生した場合、次のように書けばクリーンアップできます。
try { // チャネル作成 NetTcpBinding binding = new NetTcpBinding(); EndpointAddress address = new EndpointAddress("net.tcp://localhost:8080/Sample"); ISampleService client = ChannelFactory<ISampleService>.CreateChannel(binding, address); // サービス呼び出し client.Hoge(); // チャネルを閉じる client.Close(); } catch (CommunicationException e) { ((IChannel)client).Abort(); } catch (TimeoutException e) { ((IChannel)client).Abort(); } catch (Exception e) { ((IChannel)client).Abort(); throw; }
でも、このコードを、サービスを呼び出す箇所すべてに記述するのは大変。
次のようなヘルパークラスを用意しておくと便利です。
public class ChannelHelper<TChannel> : IDisposable where TChannel : class { private TChannel _channel; public ChannelHelper(TChannel channel) { if (channel == null) { throw new ArgumentNullException("channel"); } _channel = channel; } public TChannel Channel { get { if (_channel == null) { throw new ObjectDisposedException(this.GetType().Name); } return _channel; } } public void Dispose() { try { if (_channel != null) { if (((IChannel)_channel).State != CommunicationState.Faulted) { ((IChannel)_channel).Close(); } else { ((IChannel)_channel).Abort(); } } } catch (CommunicationException) { ((IChannel)_channel).Abort(); } catch (TimeoutException) { ((IChannel)_channel).Abort(); } catch (Exception) { ((IChannel)_channel).Abort(); throw; } finally { _channel = null; } } }
Dispose() 内で、内部に保持するチャネルを閉じるようになっています。
このクラスを利用すれば、最初のコードが次のように書けます。
NetTcpBinding binding = new NetTcpBinding(); EndpointAddress address = new EndpointAddress("net.tcp://localhost:8080/Sample"); using(ChannelHelper<ISampleChannel> helper = new ChannelHelper<ISampleChannel>( ChannelFactory<ISampleChannel>.CreateChannel(binding, address))) { helper.Channel.Hoge(); }
スッキリ♪
追記
ヘルパークラスに、static なファクトリーメソッドを用意すれば、さらにスッキリします。
public class ChannelHelper<TChannel> : IDisposable where TChannel : class { public static ChannelHelper<TChannel> Create(Binding binding, EndpointAddress address) { TChannel channel = ChannelFactory<TChannel>.CreateChannel(binding, address); return new ChannelHelper(channel); } ...(省略)... } // 使い方 NetTcpBinding binding = new NetTcpBinding(); EndpointAddress address = new EndpointAddress("net.tcp://localhost:8080/Sample"); using(ChannelHelper<ISampleChannel> helper = ChannelHelper<ISampleChannel>.Create(binding, address))) { helper.Channel.Hoge(); }