wcf其他参考异步异常和错误处理msmq.docx
《wcf其他参考异步异常和错误处理msmq.docx》由会员分享,可在线阅读,更多相关《wcf其他参考异步异常和错误处理msmq.docx(8页珍藏版)》请在冰点文库上搜索。
wcf其他参考异步异常和错误处理msmq
wcf其他参考(异步异常和错误处理msmq)
一异步
是否是异步由客户端决定,实现异步也相对简单,我们用svcutil来生成客户端代理代码的时候,只需添加/async便可以生成有异步功能的代理类了.而在IDE中,操作就更加简单,就是在添加ServiceReference的时候,选择高级选项,钩选GenerateAsynchronusoperations,如图:
生成异步操作的代理类下就会增加BeginXXX和EndXXX方法。
比如我们示例项目中服务契约中有
[OperationContract]
stringGetData(intvalue);
的操作方法,生成的代理类中对应其的异步方法为:
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true,Action="http:
//tempuri.org/IService1/GetData",ReplyAction="http:
//tempuri.org/IService1/GetDataResponse")]
System.IAsyncResultBeginGetData(intvalue,System.AsyncCallbackcallback,objectasyncState);
stringEndGetData(System.IAsyncResultresult);
另外,由于回调方法并非运行在主线程中。
如果回调方法需要更新与异步调用结果相关的界面。
我们可以使用SynchronizationContext以及它的SendOrPostCallback委托,对调用进行封送:
publicExplorerClientForm()
{
InitializeComponent();
m_synchronizationContext=SynchronizationContext.Current;
}
privateSynchronizationContextm_synchronizationContext;
则回调方法修改为:
//callbackmethod
voidOnTransferCompleted(IAsyncResultresult)
{
Streamstream=m_service.EndTransferDocument(result);
result.AsyncWaitHandle.Close();
SendOrPostCallbackcallback=delegate
{
lbMessage.Text=string.Format("Thefile{0}hadbeentransferedsucessfully.",m_doc.FileName);
};
m_synchronizationContext.Send(callback,null);
}
或者使用主窗体/控件的Invoke方法:
//异步返回时候的事件/也可以直接调用,不用通过事件
voidudpUtil_MesEvent(MesEventArgse)
{
this.Invoke(mesEventHandler,e);
}
mesEventHandler=newMesEventHandler(communnicateFromHandle);
privatevoidcommunnicateFromHandle(MesEventArgsmeg)
{
IMUtil.mesType(meg);
}
-------------------------------------------------------------------------------------
voidCallBack(IAsyncResultar)
{
Service.IService1ws=ar.AsyncStateasService.Service1Client;
stringres=ws.EndGetData(ar);
MessageBox.Show(res);
MethodInvokermi=newMethodInvoker(Compelete);
button3.Invoke(mi);
}
voidCompelete()
{
button3.Enabled=true;
}
WCF中的异步调用
WCF从理论到实践(11)-异步
二错误和异常处理
缺省模式下,服务端发生异常,客户端会获得一个Exception,但是这个Exception并不包括详细的异常信息,因为服务端并不能完全信赖客户端,比如浏览器和Web服务器之间。
为了防止非法的客户端从异常消息中获服务端的比较详细的信息,所以服务对于异常通常会比较模糊。
在进行WCF分布式应用开发的过程中,我们客户端经常会遇到一下三种常见的错误。
(1):
通信错误,可能和网络、通道等相关的异常,客户端表现为CommunicationException;
(2):
代理和通道的State,代理已经关闭,或者通道Fault,等问题,这个比较常见。
一般通道闲置时间过久,通道会出现这个状态错误的问题。
一般我们可以通过代理的State来判断。
安全验证失败也会导致这个错误。
(3):
服务调用错误,服务调用时抛出的异常,这个服务内部异常会序列化传递给客户端,被客户端捕获。
PerSession:
这种模式下,抛出异常,服务实例将销毁,客户端抛出FaultException,客户端代理对象无法继续使用
PerCall:
这种模式下,抛出异常,服务实例也将销毁。
客户端代理对象无法继续使用
Single:
这种模式下,抛出异常,服务实例会照旧运行。
客户端代理无法继续使用。
FaultException
因此如果在WCF服务中采用传统的方式处理异常,由于异常消息不能被序列化,因而客户端无法捕获和处理服务抛出的异常。
为了解决这个问题,WCF提供了FaultException。
这个是一个基于行业标准的SOAP异常类,WCF会将无法识别的异常处理为统一的FaultException异常对象,因此,可以把错误信息传递到客户端,客户端可以捕获FaultException或者Exception。
比如:
Catch(FaultExceptionex)
{
}
但是,这种情况下,比如服务端是DirectoryNotFoundException,这种情况下下却无法识别DirectoryNotFoundException所传递的错误信息。
尤为严重的是这样的异常处理方式还会导致传递消息的通道出现错误,当客户端继续调用该服务代理对象的服务操作时,会获得一个CommunicationObjectFaultedException异常,无法继续使用服务。
如果服务被设置为PerSession模式或者Single模式,异常还会导致服务对象被释放,终止服务
FaultException的另外一个重要的泛型定义就是FaultException<T>,这里我们可以使用任何系统类型或者自定义类型来传递错误信息,T代表要传递的错误细节。
FaultContract
WCF为异常处理专门提供了FaultContract特性,它可以被应用到服务操作上,指明操作可能会抛出的异常类型。
我们可以将服务所要抛出的异常类型作为FaultException<T>的类型参数,然后创建一个FaultReason对象用以传递错误消息。
客户端在调用服务代理对象时,可以捕获FaultException<DirectoryNotFoundException>异常,并且该异常不会使得通道发生错误,并且客户端可以继续使用该服务代理对象。
即使服务为PerCall服务,客户端仍然可以继续调用服务操作。
如果服务为Session服务或Singleton服务,那么即使发生了异常,服务对象也不会被终结。
DirectoryNotFoundExceptionexception=newDirectoryNotFoundException();
thrownewFaultException<DirectoryNotFoundException>(exception,
newFaultReason(string.Format("Directory{0}isnotfound.",homeDir)));
includeExceptionDetailInFaults
只是为了让客户端获得异常消息,即使不施加FaultContract特性,或者抛出非FaultException异常,我们也可以通过ServiceBehavior特性,将服务的IncludeExceptionDetailInFaults设置为true(默认为false),此时,客户端可以捕获抛出的非FaultException异常信息,但该异常仍然会导致通道出现错误
在发布服务与部署服务时,我们应避免将服务的IncludeExceptionDetailInFaults设置为true。
WCF异常处理扩展
WCF允许开发者定制异常报告和异常传递的过程。
但是要实现System.ServiceModel.Dispatcher.IErrorHandler接口:
IErrorHandler的定义如下:
publicinterfaceIErrorHandler
{
//Methods
boolHandleError(Exceptionerror);
voidProvideFault(Exceptionerror,MessageVersionversion,refMessagefault);
}
服务端抛出的异常会再调用ProvideFault()方法后再返回给客户端。
ProvideFault不考虑异常的类型。
另外ProvideFault一个重要的作用,异常提升(ExceptionPromotion)。
它可以将非FaultContract异常提升为FaultContract<T>异常,例如将OverflowException异常提升为FaultExceptino<OverflowException>异常。
例如将DirectoryNotFoundException异常提升为FaultExceptino<DirectoryNotFoundException>异常:
publicvoidProvideFault(Exceptionerror,MessageVersionversion,refMessagefault)
{
if(errorisDirectoryNotFoundException)
{
FaultException<DirectoryNotFoundException>faultException=newFaultException<DirectoryNotFoundException>(
newDirectoryNotFoundException(),newFaultReason(error.Message));
MessageFaultmessageFault=faultException.CreateMessageFault();
fault=Message.CreateMessage(version,messageFault,faultException.Action);
}
}
而HandleError()方法,我们可以重新实现代码,如log日志。
要使得错误处理扩展生效,还需要向服务通道安装错误处理扩展。
方法是让服务类实现System.ServiceModel.Description.IServiceBehavior接口:
publicclassDocumentsExplorerService:
IDocumentsExplorerService,IErrorHandler,IServiceBehavior,IDisposable
{…}然后在ApplyDispatchBehavior()方法中安装错误处理扩展:
publicvoidApplyDispatchBehavior(ServiceDescriptionserviceDescription,ServiceHostBaseserviceHostBase)
{
foreach(ChannelDispatcherdispatcherinserviceHostBase.ChannelDispatchers
{
dispatcher.ErrorHandlers.Add(this);
}
}
通过这样的处理,即使服务抛出的异常为DirectoryNotFoundException异常,并且在服务契约中没有通过FaultContract特性指定该异常,客户端同样能够获得异常的错误信息,且该异常不会导致通道发生错误,客户端可以继续调用服务代理对象的操作。
WCF从理论到实践(10):
异常处理
WCF分布式开发步步为赢(15):
错误契约(FaultContract)与异常处理(ExceptionHandle)
甩掉DTC,实现客户端控制事务-WCF的状态
三OperationContext
OperationContext为服务请求提供了对执行上下文的访问。
OperationContext.Current为请求在生命周期提供了对上下文的访问。
下面是公开的几个关键属性:
Host:
提供了对服务类型相关的ServiceHost实例的访问。
通过它,可以获取服务终端的信息/服务内容描述/以及与请求信息相关的服务行为。
Channel:
提供对回叫信道的访问。
在这种情况下,信道引用是作为一个IContextChannel引用返回的。
当调用GetCallbackChannel<T>()方法时,这个方法是由OperationContext所公开出来的,将会返回强类型信道
SessionId:
如果是一个会话的组成部分,那么该属性可以访问会话标识
ServiceSecurityContext:
为请求提供了对安全上下文的访问。