Wcf實現IServiceBehavior拓展機制

IServiceBehavior接口
描述:提供一種在整個服務內修改或插入自定義拓展機制;
命名空間:  System.ServiceModel.Description
程序集:  System.ServiceModel(在 System.ServiceModel.dll 中)
 
IServiceBehavior接口中有3個方法:
       1.AddBindingParameters:該方法能夠向綁定元素傳遞服務的自定義信息,這樣綁定元素就可向服務提供正確的支持。
       2.ApplyDispatchBehavior:該方法能夠更改運行時屬性值或插入自定義擴展對象,例如錯誤處理程序、消息或參數攔截器、安全擴展以及其餘自定義擴展對象。
       3.Validate:方法能夠在 WCF構造執行服務前檢查說明,從而確認該執行服務是否可正確執行。
 
在上面的3箇中最經常使用到的就是2和3,1本人尚未用過這裏也就不使用了!!


 
 
方法:ApplyDispatchBehavior
 
該方法應該說是這個接口最主要的方法,咱們要對服務進行自定義拓展也是經過它進行注入,下面咱們舉個例子使用IServiceBehavior對WCF服務異常的處理
你們都知道WCF通常是使用SAOP進行傳輸的,若是服務端出現異常客戶端是隻可以接收到FaultException異常,這裏咱們經過IServiceBehavior來解決使客戶端能夠接收到全部異常信息。
 
代碼:
 
    ///  <summary>
     ///  WCF服務異常處理機制,服務的行爲將默認的異常處理添加到全部通訊的調度程序中
     ///  </summary>
    [ AttributeUsage ( AttributeTargets .Class, AllowMultiple =  true )]
     public  sealed  class  ServiceErrorHandlerBehavior
        :  Attribute ,  IServiceBehavior
    {
         ///  <summary>
         ///  用於更改運行時屬性值或插入自定義擴展對象(例如錯誤處理程序、消息或參數攔截器、安全擴展以及其餘自定義擴展對象)。
         ///  </summary>
         ///  <param name="serviceDescription">  服務說明 </param>
         ///  <param name="serviceHostBase">  當前正在生成的宿主  </param>
         public  void  ApplyDispatchBehavior(  ServiceDescription  serviceDescription,  ServiceHostBase  serviceHostBase)
        {
             if  (serviceHostBase !=  null  && serviceHostBase.ChannelDispatchers.Any())
            {
                 foreach  (  ChannelDispatcher  dispatcher  in  serviceHostBase.ChannelDispatchers)
                    dispatcher.ErrorHandlers.Add(  new  InstallErrorHandler ());
            }
        }
 
         public  void  AddBindingParameters(  ServiceDescription  serviceDescription,  ServiceHostBase  serviceHostBase,  Collection < ServiceEndpoint > endpoints,  BindingParameterCollection  bindingParameters)
        {
             //當前拓展機制不適用
        }
 
         public  void  Validate( ServiceDescription  serviceDescription,  ServiceHostBase  serviceHostBase)
        {
             //當前拓展機制不適用
        }
    }
從ServiceHostBase宿主中遍歷通道調度程序集ChannellDispatchers合併在每一個ChannelDispatcher中的ErrorHandlers插入自定義異常ServiceErrorHandler,這樣的話當WCF服務出現異常時就會轉交給 Service ErrorHandler處理;
下面是InstallErrorHandler代碼:
 
    public  class  ServiceErrorHandler
        :  IErrorHandler
    {
         ///  <summary>
         ///  啓用錯誤相關處理並返回一個值,該值指示調度程序在某些狀況下是否停止會話和實例上下文。
         ///  </summary>
         ///  <param name="error"> 處理過程當中引起的異常 </param>
         ///  <returns></returns>
         public  bool  HandleError( Exception  error)
        {
             //不終止會話和實例上下文
             return  true ;
        }
 
         ///  <summary>
         ///  啓用建立從服務方法過程當中的異常返回的自定義SOAP錯誤
         ///  </summary>
         ///  <param name="error"> 服務操做過程當中引起的異常  </param>
         ///  <param name="version"> 消息的 SOAP 版本 </param>
         ///  <param name="fault"> 雙工狀況下,返回到客戶端或服務的通訊單元對象  </param>
         public  void  ProvideFault(  Exception  error,  MessageVersion  version,  ref  Message  fault)
        {
             var  faultException = error  is  FaultException  ?
                (  FaultException )error :  new  FaultException (error.Message);
 
             MessageFault  messageFault = faultException.CreateMessageFault();
            fault =  Message .CreateMessage(version, messageFault, faultException.Action);
        }
    }
 
 
下面是使用方法,很是的簡單,只須要在WCF服務類上打上ServiceErrorHandlerBehavior標記就能夠了:
代碼:
    [ ServiceErrorHandlerBehavior  ]
     public  class  Service1  :  IService1
    {
         public  string  GetData( int  value)
        {
             throw  new  Exception (  "個人測試" );
        }
    }
測試代碼:
    protected  void  Page_Load( object  sender,  EventArgs  e)
    {
         WcfWrapper <ServiceReference1.  Service1Client > wrapper =  new  WcfWrapper <ServiceReference1.  Service1Client >();
        wrapper.Using(client =>
        {
            xtResult.Text = client.GetData(1);
        });
    }
輸出結果:

「/」應用程序中的服務器錯誤。


 個人測試

說明: 執行當前 Web 請求期間,出現未經處理的異常。請檢查堆棧跟蹤信息,以瞭解有關該錯誤以及代碼中致使錯誤的出處的詳細信息。 

異常詳細信息: System.ServiceModel.FaultException: 個人測試

源錯誤: 

行 114:        
行 115:        public string GetData(int value) {
行 116: return base.Channel.GetData(value); 行 117:        }
行 118:

源文件: f:\ZcyProject\Bulrush.Library\WebTest\Service References\ServiceReference1\Reference.cs    行: 116 

固然除了使用Attribute特性也能夠在WebConfig中配置,配置也很是的簡單;
首先爲ServiceErrorHandlerBehavior建立一個Behavior的拓展配置節點,代碼以下:
 
     public  class  ServiceErrorHandlerBehaviorExtension
        :  BehaviorExtensionElement
    {
         public  override  Type  BehaviorType
        {
             get  {  return  typeof (  ServiceErrorHandlerBehavior ); }
        }
 
         protected  override  object  CreateBehavior()
        {
             return  new  ServiceErrorHandlerBehavior ();
        }
    }
配置以下:
 
  < system.serviceModel >
    < services >
      <  service  name  = "  WcfServiceTest.Service1 "  behaviorConfiguration = " defaultBehavior "  >
        <  endpoint  address  = ""  binding  = "  basicHttpBinding "  contract = " WcfServiceTest.IService1 "  >
        </  endpoint >
        <  host >
          <  baseAddresses >
            <  add  baseAddress = " http://localhost:2708/Service1.svc "  />
          </  baseAddresses >
        </  host >
      </  service >
    </ services >
    < behaviors >
      <  serviceBehaviors >
        <  behavior  name  = "  defaultBehavior "  >
          <  serviceMetadata  httpGetEnabled  = "  true "  httpsGetEnabled = " true " />
          <  serviceDebug  includeExceptionDetailInFaults  = "  false "  />
          <  ErrorBehavior  />
        </  behavior >
      </  serviceBehaviors >
    </ behaviors >
    < extensions >
      <  behaviorExtensions >
        <  add  name =  " ErrorBehavior  "
           type = " Bulrush.WCF.Behaviors.Errors.ServiceErrorHandlerBehaviorExtension, Bulrush.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null "
        />
      </  behaviorExtensions >
    </ extensions >
  </ system.serviceModel >
 
 
到這裏自定義異常處理機制就已經完成了!
 
 
方法:Validate
 
該方法主要是對當前的拓展機制進行檢查,主要檢測兩個東西 ServiceDescription服務說明和 ServiceHostBase服務宿主, 它的返回值並非bool類型而是void類型,因此標識它是否通用驗證的方式就是是否拋出異常,拋出異常表明驗證不經過。
爲了演示這個方法,咱們把上面的ServiceErrorHandler中的ProvideFault方法簡單的修改下,修改以下:
 
         public  void  ProvideFault(  Exception  error,  MessageVersion  version,  ref  Message  fault)
        {
              var  faultException = error  is  FaultException < ServiceError > ?
                (  FaultException <  ServiceError >)error :
                 new  FaultException <  ServiceError >(  new  ServiceError  { Message =  "此操做不能在這個時刻處理。請稍後嘗試。若是問題仍然存在與您的系統管理員聯繫"  });
 
             MessageFault  messageFault = faultException.CreateMessageFault();
            fault =  Message .CreateMessage(version, messageFault, faultException.Action);
        }
 
這裏ServiceError只是一個SOAP的傳輸對象,裏面只有一個Message屬性就不貼代碼了,改爲這個方式後呢,假設業務上必須讓該服務的每一個方法創建錯誤契約 [FaultContract(typeof(ServiceError))] ,雖然不創建這個服務契約服務能夠正常運行,可是全部的錯誤信息都是「 此操做不能在這個時刻處理.... 」,那麼就變的沒有意義了,因此咱們強制要求每Coder在編寫服務方法是必須創建這個錯誤契約,這個時候咱們就能夠實現Validate來檢查了,具體代碼以下:
 
     public   void  Validate(  ServiceDescription  serviceDescription, System.ServiceModel. ServiceHostBase  serviceHostBase)
    {
         bool  flag =  false ;
 
         foreach  (  var  point  in  serviceDescription.Endpoints)
        {
             foreach  (  var  operation  in  point.Contract.Operations)
            {
                 if  (operation.Faults.Count == 0)
                     throw   new   InvalidOperationException  ( string  .Format( "使用SeriveErrorHandlerBehavior機制,必須爲服務方法{0}標識 FaultContractAttribute(typeof(ServiceError)) 錯誤契約" , operation.Name));
 
                flag =  false ;
                 foreach  (  var  fault  in  operation.Faults)
                {
                     if  (fault.DetailType.Equals( typeof ( ServiceError  )))
                    {
                        flag =  true ;
                         break ;
                    }
 
                }
                 if  (!flag)
                {
                     throw   new   InvalidOperationException ( string  .Format( "使用SeriveErrorHandlerBehavior機制,必須爲服務方法{0}標識 FaultContractAttribute(typeof(ServiceError)) 錯誤契約" , operation.Name));
                }
            }
        }
    }
 
這個時候若是服務標識了 ServiceErrorHandlerBehavior拓展機制,那麼下邊的全部方法都必須創建錯誤契約,只要有一個方法沒有創建錯誤契約這個服務就沒法被連接!
    
     [  ServiceContract ]
     public   interface   IService1
    {
         //[FaultContract(typeof(ServiceError))]
        [  OperationContract ]
         string  GetData(  int  value);
    }
 
運行服務http://localhost:2708/Service1.svc 運行服務則會出現異常:

「/」應用程序中的服務器錯誤。


 使用SeriveErrorHandlerBehavior機制,必須爲服務方法GetData標識 FaultContractAttribute(typeof(ServiceError)) 錯誤契約

說明: 執行當前 Web 請求期間,出現未經處理的異常。請檢查堆棧跟蹤信息,以瞭解有關該錯誤以及代碼中致使錯誤的出處的詳細信息。 

異常詳細信息: System.InvalidOperationException: 使用SeriveErrorHandlerBehavior機制,必須爲服務方法GetData標識 FaultContractAttribute(typeof(ServiceError)) 錯誤契約
 
好了,就寫到這裏了,寫博客真心不容易,感謝那些爲咱們提供幫助的博主們!!!!
相關文章
相關標籤/搜索