【问题标题】:WCF Routing service error - ContractFilter mismatch at the EndpointDispatcherWCF 路由服务错误 - EndpointDispatcher 的 ContractFilter 不匹配
【发布时间】:2011-07-26 13:55:30
【问题描述】:

情况如下:我有一个内部服务器运行一些 WCF 服务,我希望它们可以从整个 Internet 访问。为此,我编写了一个在我们面向公众的 Web 服务器上运行的路由服务。

这个路由服务似乎可以工作,但是当我尝试调用一个方法时,我总是收到以下错误。

由于 EndpointDispatcher 的 ContractFilter 不匹配,接收方无法处理带有 Action 'http://tempuri.org/IProcessManagementService/ListProcesses' 的消息。这可能是因为合约不匹配(发送方和接收方之间的操作不匹配)或发送方和接收方之间的绑定/安全不匹配。检查发送方和接收方是否具有相同的合同和相同的绑定(包括安全要求,例如消息、传输、无)。

我已尝试从服务中删除所有安全要求,并同时使用了 wsHTTP 和 basicHTTP 端点。似乎没有什么能解决问题。然而,路由服务正确地传递了 mex 服务,因此 svcutil 能够构建客户端类。

我正在通过代码配置路由器。为路由服务提供一个服务名称列表以提供路由,以及路由器和服务器地址。

这是路由服务的配置:

<MES.RoutingService.Properties.Settings>
   <setting name="RouterAddress" serializeAs="String">
    <value>http://localhost:8781/</value>
   </setting>
   <setting name="ServerAddress" serializeAs="String">
    <value>http://10.4.1.117:8781/</value>
   </setting>
   <setting name="Services" serializeAs="Xml">
    <value>
     <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <string>ProcessManagementService</string>
      <string>TestProcessService</string>
      <string>ProcessDataEntryService</string>
      <string>ProcessReportingService</string>
     </ArrayOfString>
    </value>
   </setting>
  </MES.RoutingService.Properties.Settings>

它使用以下代码调用一个函数,从配置文件中提供路由器地址、服务器地址和服务名称。

var routers = new List<ServiceHost>();
        foreach (var service in _services)
        {
            var routerType = typeof(IRequestReplyRouter);
            var routerContract = ContractDescription.GetContract(routerType);
            var serviceHost = new ServiceHost(typeof (System.ServiceModel.Routing.RoutingService));             
            var serverEndpoints = new List<ServiceEndpoint>();              

            //Configure Mex endpoints
            serviceHost.AddServiceEndpoint(routerType, MetadataExchangeBindings.CreateMexHttpBinding(), _routerAddress + service + "/mex");
            serverEndpoints.Add(new ServiceEndpoint(routerContract, MetadataExchangeBindings.CreateMexHttpBinding(), new EndpointAddress(_serverAddress + service + "/mex")));

            //RAR SECURITY SMASH.
            var binding = new WSHttpBinding(SecurityMode.None);
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            binding.Security.Message.EstablishSecurityContext = false;
            binding.Security.Message.NegotiateServiceCredential = false;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.None;

            //Configure WsHttp endpoints
            serviceHost.AddServiceEndpoint(routerType, binding, _routerAddress + service);              
            serverEndpoints.Add(new ServiceEndpoint(routerContract, binding, new EndpointAddress(_serverAddress + service)));

            var basicBinding = new BasicHttpBinding();
            serviceHost.AddServiceEndpoint(routerType, basicBinding, _routerAddress + service + "/basic");
            serverEndpoints.Add(new ServiceEndpoint(routerContract, basicBinding, new EndpointAddress(_serverAddress + service + "/basic")));

            //Set Routing Tables
            var configuration = new RoutingConfiguration();
            configuration.FilterTable.Add(new MatchAllMessageFilter(), serverEndpoints);
            serviceHost.Description.Behaviors.Add(new RoutingBehavior(configuration));

            routers.Add(serviceHost);
        }
        return routers;

服务在启动时调用此函数,然后打开路由器列表中返回的每个服务主机。

服务器本身是通过以下app.config配置的

<system.serviceModel>
  <bindings>
   <wsHttpBinding>
    <binding name="noSecurityBinding">
     <security mode="None">
      <transport clientCredentialType="None" />
      <message establishSecurityContext="false" />
     </security>
    </binding>
   </wsHttpBinding>   
  </bindings>
  <services>
   <service name="MES.ProcessManagerServiceLibrary.ProcessManagementService">
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <endpoint binding="wsHttpBinding" bindingConfiguration="noSecurityBinding"
     contract="MES.ProcessManagerServiceLibrary.IProcessManagementService" />
    <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration=""
     contract="MES.ProcessManagerServiceLibrary.IProcessManagementService" />
    <host>
     <baseAddresses>
      <add baseAddress="http://localhost:8781/ProcessManagementService/" />
     </baseAddresses>
    </host>
   </service>
   <service name="MES.ProcessManagerServiceLibrary.TestProcessService">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="noSecurityBinding"
     contract="MES.ProcessManagerServiceLibrary.ITestProcessService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration=""
     contract="MES.ProcessManagerServiceLibrary.ITestProcessService" />    
    <host>
     <baseAddresses>
      <add baseAddress="http://localhost:8781/TestProcessService/" />
     </baseAddresses>
    </host>
   </service>
   <service name="MES.ProcessManagerServiceLibrary.ProcessDataEntryService">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="noSecurityBinding"
     contract="MES.ProcessManagerServiceLibrary.IProcessDataEntryService" />
    <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration=""
    contract="MES.ProcessManagerServiceLibrary.IProcessDataEntryService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <host>
     <baseAddresses>
      <add baseAddress="http://localhost:8781/ProcessDataEntryService/" />
     </baseAddresses>
    </host>
   </service>
   <service name="MES.ProcessManagerServiceLibrary.ProcessReportingService">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="noSecurityBinding"
     contract="MES.ProcessManagerServiceLibrary.IProcessReportingService" />
    <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration=""
    contract="MES.ProcessManagerServiceLibrary.IProcessReportingService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <host>
     <baseAddresses>
      <add baseAddress="http://localhost:8781/ProcessReportingService/" />
     </baseAddresses>
    </host>
   </service>
  </services>
  <behaviors>
   <serviceBehaviors>
    <behavior>
     <!-- To avoid disclosing metadata information, 
     set the value below to false and remove the metadata endpoint above before deployment -->
     <serviceMetadata httpGetEnabled="True"/>
     <!-- To receive exception details in faults for debugging purposes, 
     set the value below to true. Set to false before deployment 
     to avoid disclosing exception information -->
     <serviceDebug includeExceptionDetailInFaults="True"/>
    </behavior>
   </serviceBehaviors>
  </behaviors>
 </system.serviceModel>

我错过了什么?

编辑:我想我发现了问题——路由服务正在为服务返回这个配置——

<client>
   <endpoint address="http://shco-appsrv1.us.shepherd.ad:8781/ProcessManagementService/"
    binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IProcessManagementService"
    contract="IProcessManagementService" name="WSHttpBinding_IProcessManagementService" />
   <endpoint address="http://shco-appsrv1.us.shepherd.ad:8781/ProcessManagementService/basic"
    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IProcessManagementService"
    contract="IProcessManagementService" name="BasicHttpBinding_IProcessManagementService" />
 </client>

这指向内部服务器,而不是外部服务器。不知道这是否是路由服务的标准行为,或者它是否是可覆盖的行为。

【问题讨论】:

    标签: wcf wcf-routing


    【解决方案1】:

    似乎您没有在配置中正确连接 serviceModel 客户端元素。 RoutingService 需要像标准 WCF 服务一样进行配置,并且还需要向路由服务公开“拦截”端点。然后它使用客户端元素端点来重定向服务调用。

    下面是一个不依赖代码的简单配置。它包含各种路由值的命名约定,以保持一切正常。您可以将配置中的“YourRoutedService”字符串替换为您的实际服务名称,但后缀应保留以保持一切正确连接。

    我会从获得一个基于文件的配置开始,成功地进行端到端调用(使用这种方法进行调整时不需要重新编译)。接下来,将您的代码基于文件 config 并删除正在代码配置的元素。

    <system.serviceModel>
        <services
            name="System.ServiceModel.Routing.RoutingService"
            behaviorConfiguration="RoutingBehavior" >
            <endpoint
                name="RouterEndpoint"
                address=""
                binding="wsHttpBinding"
                bindingConfiguration="Http"
                contract="System.ServiceModel.Routing.IRequestReplyRouter" />
    
            <!-- List all endpoints to be routed via EndpointName routing filter -->
            <endpoint
                name="YourRoutedServiceName"
                address="YourRoutedService"
                contract="System.ServiceModel.Routing.IRequestReplyRouter"
                binding="wsHttpBinding"
                bindingConfiguration="Http" />
        </services>
        <routing>
            <filters>
                <!-- Active filters -->
                <filter
                    name="YourRoutedServiceFilter"
                    filterType="EndpointName"
                    filterData="YourRoutedServiceName" />
            </filters>
            <filterTables>
                <filterTable name="WebLayer">
                    <!-- Map to client Endpoints-->
                    <add
                        filterName="YourRoutedServiceFilter"
                        endpointName="YourRoutedServiceNameEndpoint"
                        priority="0" />
                </filterTable>
            </filterTables>
        </routing>
        <behavior name="RoutingBehavior">
            <routing routeOnHeadersOnly="false" filterTableName="WebLayer" />
            <serviceDebug includeExceptionDetailInFaults="true" />
            <serviceMetadata httpsGetEnabled="true"  />
        </behavior>
        <bindings>
            <wsHttpBinding>
                <binding name="Http">
                    <security mode="None" />
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint
                name="YourRoutedServiceNameEndpoint"
                address="http://somehost/YourRoutedService/Service.svc"
                contract="*"
                binding="wsHttpBinding"
                bindingConfiguration="Http" />
        </client>
    </system.serviceModel>
    

    【讨论】:

    • 查看我的编辑-您知道您的方法是否可以解决此类问题吗?您是否将这种方法用于 DMZ 托管路由服务?我问是因为我正在按照您的 XML 配置我的端点,我可以看到我们的方法之间的唯一区别是我没有创建特定的过滤器表,而你是。
    • 打开相应的端口后,RoutingService 就可以正常工作了。在我们的配置中,我们使用protocol bridging,因此我们可以公开 wsHttpBinding,但我们在内部使用 netTcpBinding 或 netMsmqBinding。我没有仔细查看您的代码,但如果您没有设置过滤表,那么您肯定没有正确配置 RoutingService。请记住,您需要两组端点:客户端的 RoutingService 端点和服务的实际“目标”端点。路由表是端点交叉引用。
    • 对,我正在使用 MatchAllMessageFilter() 路由。至少,它确实正确地路由了 MEX 服务。据我所知,问题在于客户端被指向内部端点而不是路由器端点。
    • MatchAllMessageFilter 仅适用于路由单个服务。如果您尝试通过单个 RoutingService 路由多个服务,则必须在路由过滤器中配对正确的端点/合同。此外,当目标服务端点合同属性未设置为“*”时,我已经看到了问题,如答案所示。不知道你会如何在代码中做到这一点。
    • 好的,所以我重新做了所有这样的事情,但我仍然在从路由器返回的 .config 中获取内部端点地址,而不是路由器的端点地址。
    猜你喜欢
    • 2019-07-20
    • 2014-04-16
    • 2013-03-09
    • 2011-03-28
    • 2013-02-21
    • 1970-01-01
    • 2011-07-26
    • 1970-01-01
    • 2018-07-05
    相关资源
    最近更新 更多