方法: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)) 错误契约
好了,就写到这里了,写博客真心不容易,感谢那些为咱们提供帮助的博主们!!!!