使用RealProxy包装多个WCF连接

时间:2012-12-06 23:44:24

标签: wcf expression realproxy

我正在开发一个项目,我们的服务器与几个暴露相同接口的服务器通信(如在群集中)。我们使用循环法来选择将请求发送到的服务器。到目前为止,我们一直使用Expression来调用我们的ClusterManager,但这导致了一些丑陋的代码。它还使单元测试变得混乱,并且有点难以验证方法参数。它似乎也会导致Moq出现一些随机异常的问题(不是本文的主题)。

我目前正在调用帖子Moq Setup for interface with action or function arguments

中记录的服务器和单元测试

关于这一点:

我目前有以下方法:

public interface IServerAdapter 
{
    void CallServer(Expression<Action<IServerExposingToClient>> methodToCall, out bool serverCalled);
}

private void DoSomething()
{
    MainViewModel.ServerAdapter.CallServer(server => server.SaveServerSettings(ServerSettings));
}

我想将此更改为以下内容:

public interface IServerAdapter 
{
    IServerExposingToClient ServerProxy { get; }
}

private void DoSomething()
{
    MainViewModel.ServerAdapter.ServerProxy.SaveServerSettings(ServerSettings);
}

ServerProxy是一个RealProxy,我需要将此调用转换为ClusterManager以执行对服务器的实际调用。目前,ClusterManager具有与CallServer相同的签名,这对于现有实现来说有点多余。为了在Invoke(IMessage)中转换调用,我有两个想法。

创意1 将IMethodCallMessage转换为lamda表达式(我无法弄清楚如何操作)并将其传递给ClusterManager。除了我不知道如何创建表达式的问题,然后再次处理返回值。某些方法返回值,而其他方法则不返回,因此这涉及保留ClusterManager.CallServer的多个重载。我还需要创建IMessage以从Invoke返回。

创意2 获取我当前用来调用服务器的WCF连接的TransparentProxy的RealProxy,并直接使用我的消息调用Invoke。在我的试验中(使用集成测试),我似乎能够成功调用服务器,但查看ReturnMessage,没有返回值,并且当ServiceChannelProxy尝试获取消息数据时,Exception属性设置为ArithmetricException。这可能是因为我在测试中做错了,或者我不能在两个单独的代理上使用相同的LogicalCallContext(或其他东西)。

有关如何处理此事的任何指示?我更喜欢 Idea 2 ,因为它似乎是最简单的,并且希望能够产生最少量的代码。在类中 IServerExposingToClient 中实现所有方法以在正确的服务器上调用不是我想要做的事情。

有关如何处理此事的任何指示?

1 个答案:

答案 0 :(得分:2)

使用找到的信息here,我已经能够解决问题。在下面的代码中,proxy是通往WCF服务的通道的ICommunicationObject。似乎工作得很好。

public override IMessage Invoke(IMessage msg)
{
    var methodCall = (IMethodCallMessage)msg;
    var proxy = FindNextProxy();
    try
    {
        MethodBase methodBase = methodCall.MethodBase;
        object[] args = methodCall.Args;
        object returnValue = methodBase.Invoke(proxy, args);
        return CreateReturnMessage(returnValue, methodCall);
    }
    catch (TargetInvocationException ex)
    {
        return CreateReturnMessage(ex.InnerException, methodCall);
    }
}