【问题标题】:How can the WCF RoutingService route callback messages from two different WCF servers with the same contract to a client?WCF RoutingService 如何将来自具有相同合同的两个不同 WCF 服务器的回调消息路由到客户端?
【发布时间】:2013-06-26 15:16:58
【问题描述】:

我的 WCF 服务器的工作方式如下:您通过调用服务方法订阅它们,例如 Subscribe()。他们通过回调通道将结果发回给您,例如 MessageReceived(string message)。

我现在的问题是我只从一个服务端点获取回调消息,而不是两者。事实上,仅通过调试,我就看到我的第二个服务甚至没有收到请求。有谁知道问题是什么?这是我的代码(注意我在 serviceAddresses 字符串中有两个 net.tcp 地址):

private void StartAggregatorHost(List<string> serviceAddresses)
{
        // Create a new service host for the routing service (note that RoutingService is a pre-defined Microsoft service model type which routes SOAP messages).
        aggregatorHost = new ServiceHost(typeof(RoutingService));

        // Set up the router address. A logger client will now connect to this address to get logged messages.
        string fqdn = System.Net.Dns.GetHostEntry("localhost").HostName;
        string routerAddress = string.Format("net.tcp://{0}:2099/LogAggregator", fqdn);

        // Set up our router binding.
        NetTcpBinding routerBinding = new NetTcpBinding(SecurityMode.None, true);
        routerBinding.SendTimeout = new TimeSpan(0, 1, 0);       
        routerBinding.ReceiveTimeout = new TimeSpan(25, 0, 0);
        routerBinding.MaxReceivedMessageSize = int.MaxValue;
        routerBinding.MaxConnections = int.MaxValue;
        routerBinding.ListenBacklog = int.MaxValue;
        routerBinding.ReliableSession.Enabled = true;
        routerBinding.ReliableSession.Ordered = true;
        routerBinding.ReliableSession.InactivityTimeout = new TimeSpan(15, 0, 0, 0);

        // Define the type of router in use. For duplex sessions like in our case, we want to use the IDuplexSessionRouter.
        Type contractType = typeof(IDuplexSessionRouter);

        // Add the endpoint that the router will use to recieve and relay messages. Note the use of System.ServiceModel.Routing.IDuplexSessionRouter.
        aggregatorHost.AddServiceEndpoint(contractType, routerBinding, routerAddress);

        // Create the endpoint list that contains the service endpoints we want to route to.
        List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>();

        foreach (string serverAddress in serviceAddresses)
        {
            // Set up our server binding(s) for each server.
            NetTcpBinding serverBinding = new NetTcpBinding(SecurityMode.None, true);
            serverBinding.SendTimeout = new TimeSpan(0, 1, 0);
            serverBinding.ReceiveTimeout = new TimeSpan(25, 0, 0);
            serverBinding.MaxReceivedMessageSize = int.MaxValue;
            serverBinding.MaxConnections = 1;
            serverBinding.ListenBacklog = int.MaxValue;
            serverBinding.ReliableSession.Enabled = true;
            serverBinding.ReliableSession.Ordered = true;
            serverBinding.ReliableSession.InactivityTimeout = new TimeSpan(15, 0, 0, 0);

            // Create the server endpoint the router will route messages to and from.
            ContractDescription contract = ContractDescription.GetContract(contractType);
            ServiceEndpoint server = new ServiceEndpoint(contract, serverBinding, new EndpointAddress(serverAddress));

            // Add the server to the list of endpoints.
            endpointList.Add(server);
        }

        // Create a new routing configuration object.
        RoutingConfiguration routingConfiguration = new RoutingConfiguration();

        // Add a MatchAll filter to the Router's filter table. Map it to the endpoint list defined earlier. When a message matches this filter, it will be sent to the endpoint contained in the list.
        routingConfiguration.FilterTable.Add(new MatchAllMessageFilter(), endpointList);

        // Attach the behavior to the service host.
        aggregatorHost.Description.Behaviors.Add(new RoutingBehavior(routingConfiguration));

        // Open the service host.
        aggregatorHost.Open();



        m_eventLog.WriteEntry(string.Format("Log aggregator service hosted at {0}.", routerAddress), EventLogEntryType.Information);

}

所以再一次......这就是我想要的:

CLIENT ---REQ---> ROUTER ---REQ---> SVC1
                         ---REQ---> SVC2

CLIENT <---CALLBACK1--- ROUTER <---CALLBACK1--- SVC1
       <---CALLBACK2---        <---CALLBACK2--- SVC2

这就是我得到的(即使我向路由器添加了第二个服务,它似乎甚至没有调用它的服务方法):

CLIENT ---REQ---> ROUTER ---REQ---> SVC1

CLIENT <---CALLBACK--- ROUTER <---CALLBACK--- SVC1

【问题讨论】:

  • 您可以检查几件事: - 当您尝试手动调用 SVC1 和 SVC2 时,它们是否正常运行? - 尝试逐个添加服务端点,而不是添加列表 - 在添加到 FilterTable 时尝试指定优先级(SVC1 和 SVC2 的优先级相同) - 首先尝试使用 XML 路由配置文件,一旦它开始工作切换到代码
  • @MaxS-Betclic - 现在就发布这个作为答案,你这个英雄。这是我错过的优先事项。我猜传入列表会自动生成优先级,因此您需要单独添加每个服务并指定其优先级: routingConfiguration.FilterTable.Add(new MatchAllMessageFilter(), new List { yourService }, 1);跨度>
  • 我在编程中违反了规则 1:不要假设任何事情都按应有的方式工作。

标签: c# wcf routing wcf-routing wcf-callbacks


【解决方案1】:

您应该设置一个特定的优先级,将 SVC1 和 SVC2 添加到 FilterTable。

routingConfiguration.FilterTable.Add(new MatchAllMessageFilter(), new List<YourServiceType> { yourService }, 1);

更多信息here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-05
    • 2011-03-04
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多