Hide REST endpoint from MEX/WSDL in WCF
I have a WCF service that has REST and SOAP endpoints for every service. This was implemented similarly to this post: REST / SOAP endpoints for a WCF service with a configuration similar to the following:
<services>
<service name="TestService"&开发者_JAVA百科gt;
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="rest" binding="webHttpBinding" contract="ITestService"/>
</service>
</services>
The problem is that the REST endpoint shows up in the resulting WSDL as an additional port and binding.
Is there any way to prevent the REST endpoint from being included in the WSDL?
You can get a copy of the WSDL, manually edit it to remove unwanted artifacts, and store it in a known location. Once you have the version of your WSDL that removes unwanted artifacts, you can redirect the ?wsdl query to that location:
<behaviors>
<serviceBehaviors>
<behavior name="TestServiceBehavior">
<serviceMetadata httpGetEnabled="True" externalMetadataLocation="http://localhost/TestService.wsdl"/>
</behavior>
</serviceBehaviors>
</behaviors>
A couple caveats about this solution. You have to be careful about what you edit. If you change critical aspects of the contract, WCF may not be able to handle messages from clients generated from it. Removing an endpoint is generally not a big deal, however changing names for bindings, operations, message types, etc. can cause problems.
You also need to be aware of imports. The WSDL generated by WCF usually defines the endpoints, then imports another .wsdl that defines the actual service contract. The service contract wsdl in tern usually imports several .xsd files that define your message and data types. You will need to make sure you have copies of these uploaded relative to the root .wsdl, and that you update the import elements to reference them appropriately.
Another issue with this is that you are now manually controlling your contract...which means if you change it, you have to edit it again and replace it on whatever site you are hosting the .wsdl file. Now, a properly designed contract should NEVER change, as that breaks one of fundamental SOA rules about web services. However, it appears that you are doing code-first development, so its something to be aware of.
It would be nice if there was an attribute to decorate the endpoint so that it is hidden from mex/wsdl generation in future versions of WCF for exactly this reason (hiding restful services from soap clients).
Found a decent way to do this using an IWsdlExportExtension
. There's probably a more robust/reusable way to do this, but this solution requires the convention of all REST endpoints to be named "REST". Below is the relevant part of an Endpoint behavior attached to all REST endpoints:
public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
// Remove all REST references (binding & port) from SOAP WSDL
foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments)
{
// Remove REST bindings
foreach (Binding binding in wsdl.Bindings)
{
if (binding.Name == "REST")
{
wsdl.Bindings.Remove(binding);
break;
}
}
// Remove REST ports
foreach (Service service in wsdl.Services)
{
foreach (Port port in service.Ports)
{
if (port.Name == "REST")
{
service.Ports.Remove(port);
break;
}
}
}
}
}
精彩评论