好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

WCF实际应用之IParameterInspector扩展

WCF实际应用之IParameterInspector扩展

 最近开发一套由客户方定制的服务,据说之前版本是通过C写的WebService。那个神奇的Service我是没见过。只是有一点,之前的验证过程居然是这样进行的:客户端发送账号、密码,Service进行验证。验证成功后,Service会将产生一个加密字符,以类似Session方式存储并发送一个加密字符串给客户端。之后客户端每次调用服务都发送这个加密字符串以供服务端进行验证合法性。虽然个人觉得极为变态,但是交涉未果。另外还有一点需求就是:服务端会有一个授权文件,这个授权文件里面存放的是对客户端接口调用的授权信息。

  基于以上原因,考虑到WCF优秀的扩展性决定对他进行一定的扩展,以完成以上需求。

  由于客户端每次发送加密字符串用作身份凭证、以及授权的需求,因此选择IParameterInspector进行扩展。

      大家都知道通过配置的方式可以使程序更加灵活。那么我们应该考虑一下如下几个问题:

    1、如何通过配置的方式实现扩展?

    2、配置以后,怎样使我们的扩展对WCF框架生效呢。?

  对于第一个问题,在WCF中,可以通过继承BehaviorExtensionElement来实现;第二个问题,将参数检测应用到终结点行为上就能实现我们预期的目标,在这个过程中还需要实现IEndpointBehavior接口。

  开始介绍之前先看看IParameterInspector接口定义:

 public   interface   IParameterInspector
 {
      ///   <summary> 
         ///   用于操作调用完成后
          ///   </summary> 
         ///   <param name="operationName">  接口操作名称  </param> 
         ///   <param name="outputs">  调用参数  </param> 
         ///   <param name="returnValue">  返回值  </param> 
         ///   <param name="correlationState">  与BeforeCall的关联状态  </param> 
     void  AfterCall( string  operationName,  object [] outputs,  object  returnValue,  object   correlationState)
        {
        }

    
       ///   <summary> 
         ///   用于操作调用前
          ///   </summary> 
         ///   <param name="operationName">  接口操作名称  </param> 
         ///   <param name="inputs">  调用参数  </param> 
         ///   <returns>  AfterCall中的correlationState。如果AfterCall需要用到correlationState,就返回;否则返回null  </returns> 
         public   object  BeforeCall( string  operationName,  object  [] inputs)
        {
    
        }
} 

  实现扩展的步骤:

  1、实现IParameterInspector接口:

     public   void  AfterCall( string  operationName,  object [] outputs,  object  returnValue,  object   correlationState)
        {
        }

          public   object  BeforeCall( string  operationName,  object  [] inputs)
        {
              //  登陆接口不做检查 
             const   string  actionName =  "  Login  "  ;
              if  (actionName ==  operationName)
            {
                  return   null  ;
            }
            Dictionary < string , Operation> dictionary =  GetAuthorizationInfo();
              if  ( 0  ==  dictionary.Count)
            {
                ServiceFaultException exception  = 
                    GetFormContainer(ConfigSetting.Instance.GetAuthorizationFileNotExistContainerName());
                  throw   new  FaultException<ServiceFaultException> (exception, exception.Reason,
                                                                FaultCode.CreateSenderFaultCode(
                                                                    exception.ErrorCode.ToString(
                                                                        CultureInfo.InvariantCulture),   string  .Empty));
            }
              if  (! dictionary.ContainsKey(operationName)
                 || Operation.Deny ==  dictionary[operationName])
            {
                ServiceFaultException exception  = 
                    GetFormContainer(ConfigSetting.Instance.GetNotAccessContainerName());
                  throw   new  FaultException<ServiceFaultException> (exception, exception.Reason,
                                                                FaultCode.CreateSenderFaultCode(
                                                                    exception.ErrorCode.ToString(
                                                                        CultureInfo.InvariantCulture),   string  .Empty));
            }
              bool  flag = inputs.Any(input => ( null  != input) &&  CacheManager.ContainsKey(input.ToString()));
              if  (! flag)
            {
                  var  exception =  GetFormContainer(ConfigSetting.Instance.GetClientTicketOutContainerName());
                  throw   new  FaultException<ServiceFaultException> (exception, exception.Details,
                                                                FaultCode.CreateSenderFaultCode(
                                                                      new   FaultCode(
                                                                        exception.ErrorCode.ToString(
                                                                            CultureInfo.CurrentCulture))));
            }
              return   null  ;
        } 

  2、实现IEndpointBehavior接口,以将参数检测应用到DispatchRuntime的Operations的参数检查器中:

   internal   class   ValidEndpointBehavior : IEndpointBehavior
    {
          #region  IEndpointBehavior Members

         public   void   AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            
        }

          public   void   ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            
        }

          public   void   ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            SynchronizedKeyedCollection < string , DispatchOperation> keyedCollection = 
                endpointDispatcher.DispatchRuntime.Operations;
              foreach  ( var  dispatchOperation  in   keyedCollection)
            {                
                dispatchOperation.ParameterInspectors.Add(  new   ParameterInspector());
            }

        }

          public   void   Validate(ServiceEndpoint endpoint)
        {
            
        }

          #endregion  
    } 

  注:以上扩展我只应用在了服务端。如果想应用在客户端,就应对ApplyClientBehavior中进行实现

  3、继承抽象类BehaviorExtesionElement,以在配置文件中配置参数检测器。

    internal   class   ExstensionBehaviorElement : BehaviorExtensionElement
    {
          public   override   Type BehaviorType
        {
              get  {  return   typeof   (ValidEndpointBehavior); }
        }

          protected   override   object   CreateBehavior()
        {
              return   new   ValidEndpointBehavior();
        }
    } 

  4、应用扩展:  

 <  system.serviceModel  > 
     <  extensions  > 
       <  behaviorExtensions  > 
         <  add   name  ="endpointExstention"  
             type  ="WcfExtensions.ExstensionBehaviorElement, WcfExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"  /> 
       </  behaviorExtensions  > 
     </  extensions  > 
     <  bindings  > 
       <  basicHttpBinding  > 
         <  binding   maxReceivedMessageSize  ="2147483647"   name  ="vrvbasicBinding"  > 
           <  readerQuotas   maxStringContentLength  ="2147483647"  /> 
         </  binding  >         
       </  basicHttpBinding  > 
     </  bindings  > 
     <  serviceHostingEnvironment  > 
       <  serviceActivations  > 
         <  add   service  ="VrvService.StateGrid.TerminalService"   relativeAddress  ="TerminalService.svc"  /> 
         <  add   service  ="VrvService.StateGrid.MapRegionService"   relativeAddress  ="MapRegionService.svc"  /> 
         <  add   service  ="VrvService.LoginService"   relativeAddress  ="LoginService.svc"  /> 
       </  serviceActivations  >       
     </  serviceHostingEnvironment  > 
     <  behaviors  > 
       <  serviceBehaviors  > 
         <  behavior  > 
           <  serviceMetadata   httpGetEnabled  ="true"  /> 
           <  serviceDebug   includeExceptionDetailInFaults  ="True"  /> 
           <  dataContractSerializer   maxItemsInObjectGraph  ="3000"  />           
         </  behavior  > 
       </  serviceBehaviors  > 
       <  endpointBehaviors  > 
         <  behavior  > 
           <  endpointExstention  /> 
         </  behavior  > 
       </  endpointBehaviors  > 
     </  behaviors  > 
   </  system.serviceModel  > 

  最后对IParameterInspector接口中AfterCall 中参数correlationState进行一下验证。我们应该如何应用它?

  我将IParameterInspector接口中BeforeCall改为如下:

         public   object  BeforeCall( string  operationName,  object  [] inputs)
        {
              //  登陆接口不做检查 
             const   string  actionName =  "  Login  "  ;
              if  (actionName ==  operationName)
            {
                  return   "  ParameterInspector operationName is Login  "  ;
            }
        } 

  然后客户端进行调用,跟踪AfterCall,如下图:

  由此可知如果想通过BeforeCall返回一些信息在AfterCall中进行处理,我们可以在BeforeCall实现中返回。

 

 

分类:  WCF应用

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于WCF实际应用之IParameterInspector扩展的详细内容...

  阅读:32次