方法: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)) 錯誤契約
好了,就寫到這裏了,寫博客真心不容易,感謝那些爲咱們提供幫助的博主們!!!!