Errore di servizio WCF Routing - ContractFilter non corrispondente al EndpointDispatcher
-
27-10-2019 - |
Domanda
La situazione è la seguente: ho un server interno che esegue alcuni servizi WCF, e voglio che siano accessibili da internet in generale. A tal fine, ho scritto un servizio di routing che è in esecuzione sul nostro fronte web-server pubblico.
Il servizio di routing sembra funzionare, ma quando tento di richiamare un metodo, ho sempre arrivare il seguente errore.
Il messaggio con azione 'http://tempuri.org/IProcessManagementService/ListProcesses' non può essere elaborato al ricevitore, a causa di una mancata corrispondenza ContractFilter al EndpointDispatcher. Questo può essere causa di una mancata corrispondenza del contratto (azioni non corrispondenti tra il mittente e il destinatario) o un / mancata corrispondenza di sicurezza vincolante tra il mittente e il destinatario. Controllare che mittente e destinatario hanno lo stesso contratto e le stesse (requisiti di sicurezza, tra cui, ad esempio, messaggio, Trasporti, None) vincolante.
Ho tentato di rimuovere tutti i requisiti di sicurezza dei servizi, e utilizzato entrambi gli endpoint wsHTTP e basicHTTP. Nulla sembra fare il trucco. Il servizio di routing è correttamente passando sui servizi mex, tuttavia, in modo svcutil è in grado di classi client build.
Io sono la configurazione del router però codice. Il servizio di routing è dato un elenco di nomi di servizi per fornire il routing per, e gli indirizzi di router e server.
Questa è la configurazione per il servizio di routing:
<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>
Si chiama una funzione con il seguente codice, fornendo l'indirizzo del router, l'indirizzo del server, e nomi di servizio dal file di configurazione.
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;
Il servizio chiama questa funzione su start, e quindi apre ognuno degli host di servizio restituiti nell'elenco dei router.
Il server stesso è configurato tramite il seguente 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>
Che cosa mi manca?
Edit: Credo di aver trovato il problema-il servizio di routing stava tornando questa configurazione per i servizi -
<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>
Questo punti al server interno, non il server esterno. Non ho idea se questo è comportamento standard per un servizio di routing, o se si tratta di un comportamento override.
Soluzione
Sembra che non hai wired-nell'elemento cliente ServiceModel nella configurazione in modo corretto. Il RoutingService deve essere configurare come un servizio WCF standard ed esporre anche gli endpoint "intercettare" ai servizi routing. Utilizza quindi i punti finali degli elementi client per reindirizzare le chiamate di servizio.
Di seguito è riportato un semplice configurazione che non si basa sul codice. Contiene convenzioni di denominazione per i diversi valori di routing che mantengono tutto dritto. È possibile sostituire la stringa "YourRoutedService" nella configurazione con il nome effettivo del servizio, ma i suffissi deve rimanere quello di tenere tutto collegato correttamente.
Vorrei iniziare con ottenere una configurazione basata su file con successo facendo end-to-end chiamate (non ricompilazioni necessarie quando tweaking con questo approccio). Avanti, basare il proprio codice sul file di configurazione e rimuovere gli elementi essendo il codice configurato.
<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>