在Windows Communication Foundation (WCF)中,标准端点是一个强大的特性,它允许开发者以一种更简洁的方式定义服务端点。通过标准端点,可以指定一个特殊的“类型”名称,它会自动配置端点的地址、绑定、契约、绑定配置和端点行为。这种特性在需要在多个项目中重复使用相同配置的端点时尤其有用。
在WCF中,通常需要为端点指定地址、绑定和契约(ABC)。如果需要对端点进行额外的配置,比如改变绑定配置或端点行为,还需要添加更多的配置。虽然可以使用WCF 4的默认配置特性,但如果有两组常见的设置,不能设置两个默认值,这样就回到了起点。
标准端点改变了定义端点的方式。通过标准端点,只需要在端点中指定一个特殊的“类型”名称,它会自动设置端点的地址、绑定、契约、绑定配置和端点行为。例如,如果定义了以下端点:
<endpoint address="mex" kind="mexEndpoint" />
上述端点将自动使用 mexHttpBinding
和 IMetadataExchange
契约。如果定义了以下端点:
<endpoint code="web" kind="webHttpEndpoint" contract="MyNS.IMyContract" />
将得到一个使用 webHttpBinding
的端点,并自动获得 webHttp
端点行为。
虽然这已经很不错了,但标准端点的真正用途在于创建自己的标准端点。想象一下,是组织中的基础设施团队的一员,需要向开发团队解释他们在项目中应该使用哪种端点配置。一种方法是发送一份备忘录给所有开发团队,希望每个人都严格按照指示操作。另一种方法是创建自己的标准端点,包含所有上述配置,然后发送给开发团队使用。
首先,需要创建自定义端点:
public class CompanyNameStandardEndpoint : ServiceEndpoint
{
private bool _isSecured;
public CompanyNameStandardEndpoint(ContractDescription contract)
: base(contract)
{
this.Binding = new NetTcpBinding();
ResetBindingConfiguration(this.Binding);
this.IsSystemEndpoint = false;
}
public bool IsSecured
{
get { return _isSecured; }
set
{
_isSecured = value;
if (_isSecured)
{
(this.Binding as NetTcpBinding).Security.Mode = SecurityMode.Transport;
}
else
{
(this.Binding as NetTcpBinding).Security.Mode = SecurityMode.None;
}
}
}
private void ResetBindingConfiguration(dynamic binding)
{
binding.SendTimeout = TimeSpan.FromMinutes(5);
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
}
}
在代码中,第8行确保端点将使用 NetTcpBinding
。第9行将调用一个初始化绑定设置的方法(第36-41行)。
注意:ResetBindingConfiguration
方法接收一个动态对象,因为出于某种原因,一些绑定属性(如 MaxReceivedMessageSize
和 MaxBufferSize
)是在每个绑定中定义的,而不是在基础 Binding
类中定义的。动态类型将允许稍后更改代码以支持TCP和HTTP绑定,而不需要为重载复制方法。
第10行指定这是一个用户定义的端点,而不是系统端点。第13-32行负责处理用户的选择,根据用户的选择将安全模式更改为 Transport
或 None
。
现在,有一个新的标准端点,它初始化绑定到 NetTcpBinding
,设置超时和消息大小,并知道根据用户的选择设置安全性。现在可以通过调用以下代码将此端点添加到服务中:
CompanyNameStandardEndpoint newEndpoint = new CompanyNameStandardEndpoint(ContractDescription.GetContract(typeof(IService1)));
newEndpoint.IsSecured = false;
newEndpoint.Address = new EndpointAddress(tcpBaseAddress + "companyUnsecured");
host.AddServiceEndpoint(newEndpoint);
要能够在配置文件中添加此端点配置,需要添加一些样板代码:
public class CompanyNameStandardEndpointCollectionElement : StandardEndpointCollectionElement<CompanyNameStandardEndpoint, CompanyNameStandardEndpointElement>
{
}
public class CompanyNameStandardEndpointElement : StandardEndpointElement
{
protected override ServiceEndpoint CreateServiceEndpoint(ContractDescription contractDescription)
{
return new CompanyNameStandardEndpoint(contractDescription);
}
public bool IsSecured
{
get { return (bool)base["isSecured"]; }
set { base["isSecured"] = value; }
}
protected override ConfigurationPropertyCollection Properties
{
get
{
ConfigurationPropertyCollection properties = base.Properties;
properties.Add(new ConfigurationProperty("isSecured", typeof(bool), false, ConfigurationPropertyOptions.None));
return properties;
}
}
protected override Type EndpointType
{
get { return typeof(CompanyNameStandardEndpoint); }
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint, ServiceEndpointElement serviceEndpointElement)
{
CompanyNameStandardEndpoint customEndpoint = (CompanyNameStandardEndpoint)endpoint;
customEndpoint.IsSecured = this.IsSecured;
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint, ChannelEndpointElement channelEndpointElement)
{
CompanyNameStandardEndpoint customEndpoint = (CompanyNameStandardEndpoint)endpoint;
customEndpoint.IsSecured = this.IsSecured;
}
protected override void OnInitializeAndValidate(ServiceEndpointElement serviceEndpointElement)
{
}
protected override void OnInitializeAndValidate(ChannelEndpointElement channelEndpointElement)
{
}
}
上述代码是一个基本的配置元素代码。最重要的部分是第13-17行,需要重复创建的每个属性在自定义标准元素中的映射(用于XML和CLR之间的映射),以及第24行,需要添加所有可以在配置文件中设置的属性,以便可以验证配置。
创建上述代码后,需要再执行一个步骤才能在配置中使用新的端点类型——需要告诉WCF有一个新的服务端点。为此,需要在 <system.serviceModel>
部分添加以下XML:
<extensions>
<endpointExtensions>
<add name="companyNameEndpoint" type="TestWcfStandardEndpoints.CompanyNameStandardEndpointCollectionElement, TestWcfStandardEndpoints" />
</endpointExtensions>
</extensions>
注意:在MSDN上,可以找到关于标准端点的良好解释,但扩展配置部分是不正确的,上述配置是正确的(正确的元素在 <extensions>
是 <endpointExtensions>
而不是文章中出现的 <standardEndpointExtensions>
)。
现在,已经准备好声明新端点并配置它们:
<services>
<service name="TestWcfStandardEndpoints.Service1">
<endpoint binding="basicHttpBinding" contract="TestWcfStandardEndpoints.IService1" />
<endpoint address="mex" kind="mexEndpoint" />
<endpoint address="companySecured" kind="companyNameEndpoint" endpointConfiguration="securedEndpoint" contract="TestWcfStandardEndpoints.IService1" />
</service>
</services>
<standardEndpoints>
<companyNameEndpoint>
<standardEndpoint isSecured="true" name="securedEndpoint" />
</companyNameEndpoint>
</standardEndpoints>
在第7-10行中,定义了具有新“类型”的端点(第9行)并指定了配置端点其余部分的位置(第10行)。第14-18行包含了创建的标准端点的配置。