初用WCF的朋友可能会遇到这样的问题,就是在使用svcutil.exe生成proxy和config的时候,或者利用add service reference添加引用的时候,部署的WCF服务到底它的metadata是什么。或者换句话说,svcutil的URL参数,以及添加服务引用时候的那个Address,到底应该填什么。

在这里我用两个最常用的Binding方式,WSHttpBinding和NetTcpBinding,分别以实际的例子来进行说明。

在这里就从MSDN上抄一个四则运算的服务来作为我们的素材。建立一个控制台程序,添加System.ServiceModel引用,然后添加下面两个文件:


ICalculatorService.cs :

WCF 服务中元数据的地址问题using System;
WCF 服务中元数据的地址问题
using System.Collections.Generic;
WCF 服务中元数据的地址问题
using System.Linq;
WCF 服务中元数据的地址问题
using System.Runtime.Serialization;
WCF 服务中元数据的地址问题
using System.ServiceModel;
WCF 服务中元数据的地址问题
using System.Text;
WCF 服务中元数据的地址问题
WCF 服务中元数据的地址问题
namespace Nocturne.Learning.WcfAddressDemo

 

CalculatorService.cs:

WCF 服务中元数据的地址问题using System;
WCF 服务中元数据的地址问题
using System.Collections.Generic;
WCF 服务中元数据的地址问题
using System.Linq;
WCF 服务中元数据的地址问题
using System.Runtime.Serialization;
WCF 服务中元数据的地址问题
using System.ServiceModel;
WCF 服务中元数据的地址问题
using System.Text;
WCF 服务中元数据的地址问题
WCF 服务中元数据的地址问题
namespace Nocturne.Learning.WcfAddressDemo
}

下面我们就分别来看看怎样HOST这个服务,怎样获取它的元数据。

WSHttpBind方式

这种方式下,元数据可以直接从http地址中获得。先看看下面这段启动服务的代码(注意,我只使用code方式启动,如果存在app.config,请将其删除)。


WCF 服务中元数据的地址问题using System;
WCF 服务中元数据的地址问题
using System.Collections.Generic;
WCF 服务中元数据的地址问题
using System.Linq;
WCF 服务中元数据的地址问题
using System.Text;
WCF 服务中元数据的地址问题
using System.ServiceModel;
WCF 服务中元数据的地址问题
using System.ServiceModel.Description;
WCF 服务中元数据的地址问题
WCF 服务中元数据的地址问题
namespace Nocturne.Learning.WcfAddressDemo
}

启动该工程,这时候就可以访问这个服务了。注意这里的baseAddress,决定了该host是采用基地址访问,而这个“访问”,仅仅是针对endpoint的位置来说的,理解这个概念非常重要。如果我们在将host.AddServiceEndpoint()的最后一个参数改为一个string,比如"CalculatorService“,影响的只是该服务的endpoint地址,对元数据没有影响。

这个时候,我们就可以通过svcutil来生成辅助文件了,命令如下:


D:\Program\temp>svcutil http://localhost:8009/MyService /language:cs /out:Proxy.cs /config:app.config
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Attempting to download metadata from 'http://localhost:8009/MyService' using WS-Metadata Exchange or DISCO.
Generating files...
D:\Program\temp\Proxy.cs
D:\Program\temp\app.config


其中的URL参数,就是代码中写到的baseAddress,在后面添加endpoint的时候不管最后那个参数写的是啥,这个命令都这么写,因为metadata是属于一个host的,并不属于一个endpoint。

如果是通过给工程添加Service Reference,也是在Address里填入这个baseAddress。如图所示:


WCF 服务中元数据的地址问题


之后该怎么玩就悉听尊便了。

NetTcpBinding方式

由于在这种方式下,服务本身是通过NetTcp方式来与客户端应答的,元数据就得另开一个mex的endpoint,来专门提供。看下面的代码:


WCF 服务中元数据的地址问题using System;
WCF 服务中元数据的地址问题
using System.ServiceModel;
WCF 服务中元数据的地址问题
using System.ServiceModel.Description;
WCF 服务中元数据的地址问题
WCF 服务中元数据的地址问题
namespace Nocturne.Learning.WcfAddressDemo
}

与前面建立WSHttpBinding的代码有两个不同的地方。首先是smb里取消了HttpGetEnabled=true的属性设置,这是由于我们的基地址不是HTTP地址,会引发异常,错误信息是:The HttpGetEnabled property of ServiceMetadataBehavior is set to true and the HttpGetUrl property is a relative address, but there is no http base address.  Either supply an http base address or set HttpGetUrl to an absolute address。第二点就是最关键的元数据地址,添加了一个MexTcpBinding绑定类型的endpoint,它就承担为整个service对外提供元数据的任务。元数据的地址就是在基址后面加了“mex”的形式,在这里就是net.tcp://localhost:8009/MyService/mex。在实际应用中,这个“mex”可以省略,即只用net.tcp://localhost:8009/MyService,系统会自动去寻找mex,而如果在前面建立endpoint的时候,用的是其它的名称(比如mex1),那就不能省略了。建议使用完整路径。


D:\Program\temp>svcutil net.tcp://localhost:8009/MyService/mex /language:cs /out:Proxy.cs /config:app.config
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Attempting to download metadata from 'net.tcp://localhost:8009/MyService' using WS-Metadata Exchange. This URL does not support DISCO.
Generating files...
D:\Program\temp\Proxy.cs
D:\Program\temp\app.config


Add Service Reference的操作类同。

小结

Address和元数据,是部署WCF服务时最最基本的概念,有必要非常熟练地掌握,笔者也只是对常用的两种绑定方式做了一个讨论,更多的内容还有待发掘。

相关文章: