zoukankan      html  css  js  c++  java
  • CustomBehavior 入门

    由于最近工作一直在做wcf平台上的开发,所以决定先结合自己平时工作中的经验实践写一个WCF的系列,希望能对大家有所帮助。

       首先,说到WCF,就不得不提Endpoint这个概念,而Endpoint则由ABC组成,Adress,BindingContract。对于这些基础的知识,我向大家推荐Artech写的一个系列,大家可以去读一下,我觉得写得非常好,读罢获益匪浅。

        http://www.cnblogs.com/artech/archive/2007/02/28/659331.html

    接着来说ABC的问题。在Binding里面我们只能指定编码方式而不能指定序列化的方式,序列化的方式只能在程序里面指定。而最近我们的team遇到了这样一个需求,大致要求如下:

    1. 1.       我们team当前研发的web servicerestful的,而我们希望用户能在request里面输入一个”alt=xml”或者”alt=json”来决定返回的数据格式是xml或者json
    2. 2.       我们希望动态决定返回数据这个功能是独立的,可插拔的模块,并且可以方便地决定哪些service用这个功能而哪些service不用这个功能
    3. 3.       我们希望可以通过配置的方式来插拔这个功能

     好了,大致需求就这么多。针对以上需求,我们想到写一个Custom Behavior来实现这些需求。

     对于Custom Behavior, 先做一点基本知识的阐述:

       我们可以在五个不同的点来定制我们自己的Custom Behavior

       ParameterInspection

       MessageFormatting

       OperationInvoker

       MessageInspection

       OperationSelector

       由于这个需求是需要根据用户输入的参数来动态的决定返回的response的格式,所以我当时选择写一个MessageFormatterCustomBehavior

       然后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系列
    标签: WCFCustomBehavior
  • 相关阅读:
    【开发笔记】- Linux命令大全
    【面试突击】- SpringMVC那些事(一)
    【阿里云开发】- 搭建和卸载svn服务器
    【阿里云开发】- 安装tomcat
    SpringCloud之Eureka服务发现和注册(二)
    springcloud之环境工程模块(一)
    java多线程中篇(三) —— 线程的控制(创建,运行,阻塞,中断,结束)
    java多线程中篇(二) —— 线程的创建和Synchronized锁关键字
    java多线程中篇(一) —— Thread详情
    JUC之AbstractQueuedSynchronizer原理分析
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2562784.html
Copyright © 2011-2022 走看看