从WCF中的MEX / WSDL隐藏REST端点

时间:2010-03-02 01:12:46

标签: wcf rest soap wsdl

我有一个WCF服务,每个服务都有REST和SOAP端点。这与此帖子的实现类似:REST / SOAP endpoints for a WCF service,其配置类似于以下内容:

<services>
  <service name="TestService">
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    <endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
    <endpoint address="rest" binding="webHttpBinding" contract="ITestService"/>
  </service>
</services>

问题是REST端点在生成的WSDL中显示为附加端口和绑定。

有没有办法阻止REST端点包含在WSDL中?

3 个答案:

答案 0 :(得分:1)

您可以获取WSDL的副本,手动编辑它以删除不需要的工件,并将其存储在已知位置。获得可删除不需要的工件的WSDL版本后,可以将?wsdl查询重定向到该位置:

<behaviors>
 <serviceBehaviors>
    <behavior name="TestServiceBehavior">
     <serviceMetadata httpGetEnabled="True" externalMetadataLocation="http://localhost/TestService.wsdl"/>
    </behavior>
 </serviceBehaviors>
</behaviors>

关于此解决方案的一些注意事项。您必须小心编辑的内容。如果更改合同的关键方面,WCF可能无法处理从其生成的客户端的消息。删除端点通常不是什么大问题,但更改绑定,操作,消息类型等名称可能会导致问题。

您还需要注意进口。 WCF生成的WSDL通常定义端点,然后导入另一个定义实际服务契约的.wsdl。服务合同wsdl in tern通常会导入几个定义消息和数据类型的.xsd文件。您需要确保拥有相对于根.wsdl上载的这些副本,并更新导入元素以适当地引用它们。

此问题的另一个问题是您现在手动控制合同...这意味着如果您更改它,则必须再次编辑它并在托管.wsdl文件的任何网站上替换它。现在,一个设计合理的合同永远不会改变,因为这违反了有关Web服务的基本SOA规则之一。但是,您似乎正在进行代码优先开发,因此需要注意一些事项。

答案 1 :(得分:1)

如果有一个属性来装饰端点,那么在WCF的未来版本中将其隐藏于mex / wsdl生成就好了,原因正是如此(隐藏来自soap客户端的休息服务)。

答案 2 :(得分:1)

使用IWsdlExportExtension找到体面的方法。可能有更强大/可重用的方法来执行此操作,但此解决方案要求将所有REST端点的约定命名为“REST”。以下是附加到所有REST端点的端点行为的相关部分:

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;
                }
            }
        }
    }  
}