基于上文的Demo,我们观察到,在IIS宿主中,配置文件有以下特征:
<system.serviceModel> <services> <service name="WcfService9.Service1" behaviorConfiguration="WcfService9.Service1Behavior"> <endpoint address="" binding="wsHttpBinding" contract="WcfService9.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService9.Service1Behavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
下面修改这个配置文件,看怎么搞死WCF:
1.删除MEX终结点:
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
一切照常,Service可以运行,Client也可以调用Service的方法。
2.不删除MEX终结点,只删除行为中的serviceMetadata 标签:
<serviceMetadata httpGetEnabled="true"/>
会发现Service不能运行,更不要说Client能调用Service了。
具体异常信息如下所示:
The contract name 'IMetadataExchange' could not be found in the list of contracts implemented by the service Service1. Add a ServiceMetadataBehavior to the configuration file or to the ServiceHost directly to enable support for this contract.
3.怎么办?干脆连MEX那一行也删了,新的配置文件如下所示:
<system.serviceModel> <services> <service name="WcfService9.Service1" behaviorConfiguration="WcfService9.Service1Behavior"> <!-- Service Endpoints --> <endpoint address="" binding="wsHttpBinding" contract="WcfService9.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService9.Service1Behavior"> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
于是,Service又能运行了,
但是,因为没有公布MEX元数据交换中间点,所以,我们不能在Client端添加对Service的引用:
4.好吧,看来我们要想在httpGetEnabled上做文章,只能保留MEX终结点。既然删除<serviceMetadata httpGetEnabled="true"/> 这个标签会导致Service不能运行,我们在删除httpGetEnabled属性的同时,保留这个标签,如下所示:
<system.serviceModel> <services> <service name="WcfService9.Service1" behaviorConfiguration="WcfService9.Service1Behavior"> <endpoint address="" binding="wsHttpBinding" contract="WcfService9.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService9.Service1Behavior"> <serviceMetadata/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
我们发现,Service又能运行了,但是http://localhost:40159/Service1.svc页面与前面成功运行起来的页面不太一样:
尽管如此,我们还是能够正常使用这个Service:
5.哦,原来是这样。看来<serviceMetadata httpGetEnabled="true"/>是不能赶尽杀绝的,至少要保留一个<serviceMetadata/>标签。
我们将配置文件修改为:
<serviceMetadata httpGetEnabled="false"/>
,再次运行Service,会发现和<serviceMetadata/>具有相同的效果。可见,httpGetEnabled默认值为false。
6.我们在第4次测试中,发现<serviceMetadata httpGetEnabled="true"/>和<serviceMetadata httpGetEnabled="false"/>所产生的Service页面不同:
但是,Client都是可以调用Service的。那么差异到底在哪里呢?
经测试,在MEX终结点存在的情况下,是否设置httpGetEnabled是没有区别的。
但是,如果删除MEX终结点,差异就出来了:
对于<serviceMetadata httpGetEnabled="true"/>,我们发现,Service可以运行,Client也可以调用Service。
而对于<serviceMetadata httpGetEnabled="false"/>,这就是测试3的情形了,Service虽然可以运行,但是因为没有公布元数据终结点,所以Client不能调用Service。
好了,可以结案陈词了。
MEX和httpGetEnabled是公布元数据终结点的两种不同方式。
MEX可以适用于任何binding,比如说TCP、HTTP。
httpGetEnabled则仅适用于HTTP。
那好,既然我们现在就处于IIS宿主的环境下,那么二者就都可以使用。
1)只设置MEX是不够的,在此基础上,我们还要设置httpGetEnabled="true"
2)只设置<serviceMetadata httpGetEnabled="true"/>就够了。
此外,最恶心的莫过于,如果不设置<serviceMetadata httpGetEnabled="true"/>,但是仍然要保留<serviceMetadata>标签。我猜,这也许源于自定义behavior的设计原理。在配置文件中必须要声明这个标签,哪怕是一个空标签,也要保留,从而在WCF运行起来的时候,会找到这个serviceMetadata标签,进行实例化(设置httpGetEnabled默认值为false)。
此时,我已经能想象到WCF设计团队脸上的无奈了。