CustomBehavior 入门
由于最近工作一直在做 wcf 平台上的开发,所以决定先结合自己平时工作中的经验实践写一个 WCF 的系列,希望能对大家有所帮助。
首先,说到 WCF ,就不得不提 Endpoint 这个概念,而 Endpoint 则由 ABC 组成, Adress,Binding 和 Contract 。对于这些基础的知识,我向大家推荐 Artech 写的一个系列,大家可以去读一下,我觉得写得非常好,读罢获益匪浅。
http://www.cnblogs.com/artech/archive/2007/02/28/659331.html
接着来说 ABC 的问题。在 Binding 里面我们只能指定编码方式而不能指定序列化的方式,序列化的方式只能在程序里面指定。而最近我们的 team 遇到了这样一个需求,大致要求如下:
1. 我们 team 当前研发的 web service 是 restful 的,而我们希望用户能在 request 里面输入一个 ”alt=xml” 或者 ”alt=json” 来决定返回的数据格式是 xml 或者 json 2. 我们希望动态决定返回数据这个功能是独立的,可插拔的模块,并且可以方便地决定哪些 service 用这个功能而哪些 service 不用这个功能 3. 我们希望可以通过配置的方式来插拔这个功能好了,大致需求就这么多。针对以上需求,我们想到写一个 Custom Behavior 来实现这些需求。
对于 Custom Behavior, 先做一点基本知识的阐述:
我们可以在五个不同的点来定制我们自己的 Custom Behavior
ParameterInspection
MessageFormatting
OperationInvoker
MessageInspection
OperationSelector
由于这个需求是需要根据用户输入的参数来动态的决定返回的 response 的格式,所以我当时选择写一个 MessageFormatter 的 CustomBehavior
然后 CustomBehavior 分以下几种:
ServiceBehavior
EndpointBehavior
ContractBehavior
OperationBehavior
在 WCF 里面,有三种方式来添加 behavior:
ServiceBehavior
EndpointBehavior
ContractBehavior
OperationBehavior
通过代码方式添加
√
√
√
√
通过 Attribute 的方式
√
×
√
√
通过配置的方式
√
√
×
×
好了根据以上阐述,由于我们想使用配置来插拔该功能,所以我们选用 Endpoint Behavior
然后,我们可以自己实现一个IDispatchMessageFormatter
public class MessageFormatter : IDispatchMessageFormatter
{
private const string CONTENT_TYPE_XML = "text/xml";
private const string CONTENT_TYPE_JSON = "application/Json";
private readonly IDispatchMessageFormatter originalFormatter;
public MessageFormatter(IDispatchMessageFormatter dispatchMessageFormatter)
{
this.originalFormatter = dispatchMessageFormatter;
}
#region IDispatchMessageFormatter
public void DeserializeRequest(Message message, object[] parameters)
{
this.originalFormatter.DeserializeRequest(message,parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
}
#endregion
}
我们需要实现反序列化和序列化的2个方法。
而根据现有的需求,我们可以用WCF中默认的DataContract序列化,因为DataContract序列化既可以序列化出xml也可以序列化出Json,所以我们只需要给Model打上DataContract标签和DataMember标签即可。
我们可以在SerializeReply方法中做如下操作
string alt = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters["alt"];
if(alt=="xml")
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;
WebOperationContext.Current.OutgoingResponse.ContentType = CONTENT_TYPE_XML;
}
if(alt=="json")
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;
WebOperationContext.Current.OutgoingResponse.ContentType = CONTENT_TYPE_JSON;
}
然后,我们需要把这个MessageFormatter加到一个EndpointBehavior里面去。
我们可以实现一个Endpoint Behavior
public class MessageFormatterEndpointBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
operation.Formatter = new MessageFormatter(operation.Formatter);
}
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}
接下来,由于Endpoint Behavior是不能直接写进配置文件中的,为了实现可配置,我们需要为我们的Endpoint Behavior写一个Extension Element.
public class MessageFormatterEndpointBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(MessageFormatterEndpointBehavior); }
}
protected override object CreateBehavior()
{
return new MessageFormatterEndpointBehavior();
}
}
然后,再把这个extension element配置到文件中。
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webBinding">
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="WCFMessageFormatter.Services.TankService" behaviorConfiguration="testServiceBehavior">
<endpoint address="http://localhost:8080/TankService" behaviorConfiguration="webBehavior"
binding="webHttpBinding" bindingConfiguration="webBinding" contract="WCFMessageFormatter.Contracts.ServiceContracts.ITankService">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
<endpointMessageFormatter />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="testServiceBehavior">
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add
name="endpointMessageFormatter"
type="WCFMessageFormatter.CustomServiceBehaviors.MessageFormatterEndpointBehaviorExtensionElement, WCFMessageFormatter.CustomServiceBehaviors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,System.Web.Routing,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35" />
</modules>
</system.webServer>
</configuration>
好了,这样一来就可以实现我们需求中提到的功能了。
在下一节中,我将继续这个例子来说说WCF Custom Behavior和序列化的相关内容,下一篇中将提到几个需求变化以及我们如何应对这些变化。
在这个例子写完时我将附上完整的项目代码。
另外,最近也有一些朋友通过博客园上的联系方式与我联系,时间关系,我并不能对所有问题都做出回答,十分抱歉,大家有任何问题还是可以给我留言,或者邮件,QQ联系,我会尽量回复。
分类: WCF系列
标签: WCF , CustomBehavior
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于CustomBehavior 入门的详细内容...