创建你自己的(自定义)标准终结点(WCF 4)





5.00/5 (3投票s)
在 WCF 4 中创建自定义的标准终结点
最近,我一直在编写和讲述关于 WCF 4.5 的内容,但在昨天在 Visual Studio Live 中进行我的“WCF 4 中的新增功能”演讲时,我意识到 WCF 4 有一个特性大多数人都没有意识到,也不真正理解它的用处——标准终结点。
在 WCF 中,我们总是需要为我们的终结点指定一组地址+绑定+契约 (ABC)。如果我们的终结点还需要配置,例如——更改绑定配置或终结点行为,那么我们需要添加更多的配置。 我们可以使用默认配置(WCF 4 的另一个特性),但是如果我们有两个常用设置,我们无法设置两个默认值,然后我们又回到了原点。
标准终结点改变了我们定义终结点的方式——通过标准终结点,我们在终结点中指定一个特殊的“kind”名称,它会自动设置我们终结点的地址、绑定、契约、绑定配置和终结点行为。
例如——如果我们定义了以下终结点
<endpoint address="mex" kind="mexEndpoint"/>
上面的终结点将自动设置为 mexHttpBinding
和 IMetadataExchange
契约。
如果我们定义以下终结点
<endpoint code="web" kind="webHttpEndpoint" contract="MyNS.IMyContract"/>
我们将获得一个使用 webHttpBinding
的终结点,并自动获取 webHttp
终结点行为。
虽然这非常好,但这是我们使用标准终结点所能做的最少的事情。标准终结点的真正用途在于创建你自己的终结点。
想象一下——你是你组织的基础架构团队的一员,你需要向开发团队解释他们应该在他们的项目中使用哪种终结点配置——“请使用 NetTcp 绑定,具有增加的消息大小限制,安全级别为无或传输,并且不要忘记增加发送超时”。
一种方法是向所有开发团队发送备忘录,希望每个人都完全按照你的指示去做。另一种方法是创建你自己的标准终结点,其中包含以上所有配置,然后将其发送给开发团队使用。
首先,你需要创建你的自定义终结点
1: public class CompanyNameStandardEndpoint : ServiceEndpoint
2: {
3: private bool _isSecured;
4:
5: public CompanyNameStandardEndpoint(ContractDescription contract)
6: : base(contract)
7: {
8: this.Binding = new NetTcpBinding();
9: ResetBindingConfiguration(this.Binding);
10: this.IsSystemEndpoint = false;
11: }
12:
13: public bool IsSecured
14: {
15: get
16: {
17: return _isSecured;
18: }
19: set
20: {
21: _isSecured = value;
22: if (_isSecured)
23: {
24: (this.Binding as NetTcpBinding).Security.Mode = SecurityMode.Transport;
25: }
26: else
27: {
28: (this.Binding as NetTcpBinding).Security.Mode = SecurityMode.None;
29: }
30: }
31:
32: }
33:
34: // Receive a dynamic object instead of creating separate methods
35: // for netTcp, basicHttp, WSHttpBinding...
36: private void ResetBindingConfiguration(dynamic binding)
37: {
38: binding.SendTimeout = TimeSpan.FromMinutes(5);
39: binding.MaxReceivedMessageSize = Int32.MaxValue;
40: binding.MaxBufferSize = Int32.MaxValue;
41: }
42: }
第 8 行确保你的终结点将使用 NetTcp 绑定。
第 9 行将调用一个初始化绑定设置的方法(第 36-41 行)。
注意:ResetBindingConfiguration
方法接收一个动态对象,因为由于某些原因,某些绑定属性(例如 MaxReceivedMessageSize
和 MaxBufferSize
)是在每个绑定中定义的,而不是在基 Binding
类中定义的。动态对象将允许我们在以后更改我们的代码以支持 TCP 和 HTTP 绑定,而无需为重载复制我们的方法。
第 10 行指定这是一个用户定义的终结点,而不是系统终结点。
第 13-32 行负责处理用户是否选择保护终结点,方法是将安全模式更改为 Transport
或 None
。
所以现在,我们有一个新的标准终结点,它将绑定初始化为 NetTcpBinding
,设置超时和消息大小,并且知道根据用户的选择设置安全性。我们现在可以通过调用以下代码在代码中将此终结点添加到我们的服务中
1: CompanyNameStandardEndpoint newEndpoint = new CompanyNameStandardEndpoint(
2: ContractDescription.GetContract(typeof(IService1)));
3:
4: newEndpoint.IsSecured = false;
5: newEndpoint.Address = new EndpointAddress(tcpBaseAddress + "companyUnsecured");
6:
7: host.AddServiceEndpoint(newEndpoint);
为了能够在 *config* 文件中添加此终结点配置,你需要添加一些样板代码
1: public class CompanyNameStandardEndpointCollectionElement :
2: StandardEndpointCollectionElement<CompanyNameStandardEndpoint,
CompanyNameStandardEndpointElement>
3: {
4: }
5:
6: public class CompanyNameStandardEndpointElement : StandardEndpointElement
7: {
8: protected override ServiceEndpoint CreateServiceEndpoint
(ContractDescription contractDescription)
9: {
10: return new CompanyNameStandardEndpoint(contractDescription);
11: }
12:
13: public bool IsSecured
14: {
15: get { return (bool)base["isSecured"]; }
16: set { base["isSecured"] = value; }
17: }
18:
19: protected override ConfigurationPropertyCollection Properties
20: {
21: get
22: {
23: ConfigurationPropertyCollection properties = base.Properties;
24: properties.Add(new ConfigurationProperty("isSecured",
typeof(bool), false, ConfigurationPropertyOptions.None));
25: return properties;
26: }
27: }
28:
29: protected override Type EndpointType
30: {
31: get { return typeof(CompanyNameStandardEndpoint); }
32: }
33:
34: protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ServiceEndpointElement serviceEndpointElement)
35: {
36: CompanyNameStandardEndpoint customEndpoint = (CompanyNameStandardEndpoint)endpoint;
37: customEndpoint.IsSecured = this.IsSecured;
38: }
39:
40: protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ChannelEndpointElement channelEndpointElement)
41: {
42: CompanyNameStandardEndpoint customEndpoint = (CompanyNameStandardEndpoint)endpoint;
43: customEndpoint.IsSecured = this.IsSecured;
44: }
45:
46: protected override void OnInitializeAndValidate(
ServiceEndpointElement serviceEndpointElement)
47: {
48:
49: }
50:
51: protected override void OnInitializeAndValidate(
ChannelEndpointElement channelEndpointElement)
52: {
53:
54: }
55: }
上面的代码是一个基本的配置元素代码。最重要的部分是第 13-17 行,你需要重复你在自定义标准元素中创建的每个属性(用于 XML 和 CLR 之间的映射),以及第 24 行,你在其中添加可以在配置文件中设置的所有属性,以便可以验证配置。
创建以上代码后,你只需要一个步骤即可在你的配置中使用新的终结点类型——你需要告诉 WCF 你有一个新的服务终结点。为此,你需要在你的 <system.serviceModel>
部分中添加以下 XML
1: <extensions>
2: <endpointExtensions>
3: <add
4: name="companyNameEndpoint"
5: type="TestWcfStandardEndpoints.CompanyNameStandardEndpointCollectionElement,
TestWcfStandardEndpoints"/>
6: </endpointExtensions>
7: </extensions>
注意:在 MSDN 上,你可以找到关于标准终结点的良好解释,但扩展配置部分不正确,以上配置是正确的配置(<extensions>
中的正确元素是 <endpointExtensions>
,而不是文章中出现的 <standardEndpointExtensions>
)。
现在,你可以声明你的新终结点并配置它们了
1: <services>
2: <service name="TestWcfStandardEndpoints.Service1">
3: <endpoint binding="basicHttpBinding"
4: contract="TestWcfStandardEndpoints.IService1"/>
5: <endpoint address="mex"
6: kind="mexEndpoint" />
7: <endpoint address="companySecured"
8: kind="companyNameEndpoint"
9: endpointConfiguration="securedEndpoint"
10: contract="TestWcfStandardEndpoints.IService1"/>
11: </service>
12: </services>
13:
14: <standardEndpoints>
15: <companyNameEndpoint>
16: <standardEndpoint isSecured="true" name="securedEndpoint"/>
17: </companyNameEndpoint>
18: </standardEndpoints>
在第 7-10 行中,我们使用新的“kind”(第 9 行)定义终结点,并指定我们在哪里配置终结点的其余部分(第 10 行)。
第 14-18 行包含我们创建的标准终结点的配置。
总而言之,标准终结点是一种创建具有绑定配置、契约设置和终结点行为的完全配置的终结点的简便方法。 当你想在多个项目中一遍又一遍地创建相同的终结点时(这在 99.99% 的情况下会发生),它非常有用。
不要费心复制粘贴以上所有代码——你只需从此处下载完整的解决方案。