RealProxy を使った WCF サービスクライアント

「チャネル生成→サービス呼び出し→チャネルを閉じる」という処理を、サービスを呼び出すたびに記述するのは面倒です。できれば、これらの処理を一度のメソッド呼び出しで完結させたい。

何か上手い方法がないか考えたところ、RealProxy を使う方法を思いつきました。

public class ServiceProxy<TChannel> : RealProxy where TChannel : class
{
    private Binding _binding;
    private EndpointAddress _address;

    public ServiceProxy(Binding binding, EndpointAddress address)
        : base(typeof(TChannel))
    {
        _binding = binding;
        _address = address;
    }

    public override IMessage Invoke(IMessage msg)
    {
        // チャネル生成
        TChannel channel = ChannelFactory<TChannel>.CreateChannel(
            _binding,
            _address);

        IMethodMessage methodMsg = (IMethodMessage)msg;

        // サービス呼び出し
        object returnValue = typeof(TChannel).InvokeMember(methodMsg.MethodName,
            BindingFlags.InvokeMethod,
            null,
            channel,
            methodMsg.Args);

        ReturnMessage returnMsg = new ReturnMessage(
            returnValue,
            null,
            0,
            methodMsg.LogicalCallContext,
            (IMethodCallMessage)msg);

        // チャネルを閉じる
        ((IClientChannel)channel).Close();

        return returnMsg;
    }
}

public static class ServiceProxyFactory<TChannel> where TChannel : class
{
    public static TChannel Create(Binding binding, EndpointAddress address)
    {
        return new ServiceProxy<TChannel>(binding, address).GetTransparentProxy() as TChannel;
    }
}

使い方はいたって簡単。

// プロキシ生成
IHogeService proxy = ServiceProxyFactory<IHogeService>.Create(
    new NetTcpBinding(),
    new EndpointAddress(address));

// サービス呼び出し
proxy.HogeHoge();

ChannelFactory で生成されるオブジェクトは TransparentProxy だったけど、InvokeMember でサービスを呼び出すことができました。

これは使い勝手が良さそう。