WCF异常处理特点体现
创始人
2024-06-23 06:40:11
0次

WCF的出现,为开发人员带来了不一样的体验。在很多方面都有所改变,为编程者提供了一个非常好的开发环境。比如今天为大家介绍的WCF异常处理,就有许多特殊之处,值得我们去深入的研究。

异常消息与特定技术有关,.NET异常同样如此,因而WCF并不支持传统的异常处理方式。如果在WCF服务中采用传统的方式处理异常,由于异常消息不能被序列化,因而客户端无法收到服务抛出的异常,例如这样的服务设计:

  1. [ServiceContract(SessionModeSessionMode = SessionMode.Allowed)]  
  2. public interface IDocumentsExplorerService  
  3. {  
  4. [OperationContract]   
  5. DocumentList FetchDocuments(string homeDir);  
  6. }  
  7. [ServiceBehavior(InstanceContextModeInstanceContextMode
    =InstanceContextMode.Single)]  
  8. public class DocumentsExplorerService : 
    IDocumentsExplorerService,IDisposable  
  9. {  
  10. public DocumentList FetchDocuments(string homeDir)  
  11. {  
  12. //Some Codes  
  13. if (Directory.Exists(homeDir))  
  14. {  
  15. //Fetch documents according to homedir  
  16. }  
  17. else  
  18. {  
  19. throw new DirectoryNotFoundException(  
  20. string.Format("Directory {0} is not found.",homeDir));  
  21. }  
  22. }  
  23. public void Dispose()  
  24. {   
  25. Console.WriteLine("The service had been disposed.");  
  26. }  
  27. } 

 

则客户端在调用如上的服务操作时,如果采用如下的捕获方式是无法获取该异常的:

  1. catch (DirectoryNotFoundException ex)  
  2. {  
  3. //handle the exception;  
  4. } 

 

为了弥补这一缺陷,WCF异常处理会将无法识别的异常均当作为FaultException异常对象,因此,客户端可以捕获FaultException或者Exception异常:

  1. catch (FaultException ex)  
  2. {  
  3. //handle the exception;  
  4. }  
  5. catch (Exception ex)  
  6. {  
  7. //handle the exception;  
  8. } 

然而,这样捕获的异常,却无法识别DirectoryNotFoundException所传递的错误信息。尤为严重的是这样的异常处理方式还会导致传递消息的通道出现错误,当客户端继续调用该服务代理对象的服务操作时,会获得一个CommunicationObjectFaultedException异常,无法继续使用服务。如果服务被设置为PerSession模式或者Single模式,异常还会导致服务对象被释放,终止服务。

WCF异常处理专门提供了FaultContract特性,它可以被应用到服务操作上,指明操作可能会抛出的异常类型。例如前面的服务契约就可以修改为:

  1. [ServiceContract(SessionModeSessionMode = SessionMode.Allowed)]  
  2. public interface IDocumentsExplorerService  
  3. {  
  4. [OperationContract]  
  5. [FaultContract(typeof(DirectoryNotFoundException))]  
  6. DocumentList FetchDocuments(string homeDir);  
  7. } 

 

然而,即使通过FaultContract指定了操作要抛出的异常,然而如果服务抛出的异常并非FaultException或者FaultException异常,同样会导致通道发生错误。因此在服务实现中,正确的实现应该如下:

  1. public class DocumentsExplorerService : 
    IDocumentsExplorerService,IDisposable  
  2. {  
  3. public DocumentList FetchDocuments(string homeDir)  
  4. {  
  5. //Some Codes  
  6. if (Directory.Exists(homeDir))  
  7. {  
  8. //Fetch documents according to homedir  
  9. }  
  10. else  
  11. {  
  12. DirectoryNotFoundException exception = 
    new DirectoryNotFoundException();  
  13. throw new FaultException
    (exception,   
  14. new FaultReason(string.Format("Directory {0} 
    is not found.", homeDir)));  
  15. }  
  16. }  
  17. } 

 

我们可以将服务所要抛出的异常类型作为FaultException的类型参数,然后创建一个FaultReason对象用以传递错误消息。客户端在调用服务代理对象时,可以捕获FaultException< DirectoryNotFoundException>异常,并且该异常不会使得通道发生错误,并且客户端可以继续使用该服务代理对象。即使服务为PerCall服务,客户端仍然可以继续调用服务操作。如果服务为Session服务或Singleton服务,那么即使发生了异常,服务对象也不会被终结。#t#

如果只是为了让客户端获得异常消息,即使不施加FaultContract特性,或者抛出非FaultException异常,我们也可以通过ServiceBehavior特性,将服务的IncludeExceptionDetailInFaults设置为true(默认为false),此时,客户端可以捕获抛出的非FaultException异常信息,但该异常仍然会导致通道出现错误。

但是,在发布服务与部署服务时,我们应避免将服务的IncludeExceptionDetailInFaults设置为true。

如果不希望使用FaultContract,同时又要保证服务抛出的WCF异常处理能够被客户端捕获,并且不会导致通道错误,我们还可以通过错误处理扩展的方式实现。此时,我们可以将服务本身作为错误处理对象,令其实现System.ServiceModel.Dispatcher.IErrorHandler接口:

  1. public class DocumentsExplorerService : 
    IDocumentsExplorerService,IErrorHandler, IDisposable  
  2. {…} 

 

在该接口的ProvideFault()方法中,可以将非FaultContract异常提升为FaultContract异常,例如将DirectoryNotFoundException异常提升为FaultExceptino异常:

  1. public void ProvideFault(Exception error,
     MessageVersion version, ref Message fault)  
  2. {  
  3. if (error is DirectoryNotFoundException)  
  4. {  
  5. FaultException faultException =
     new FaultException(  
  6. new DirectoryNotFoundException(), new FaultReason(error.Message));  
  7. MessageFault messageFault = faultException.CreateMessageFault();  
  8. fault = Message.CreateMessage(version,messageFault,
    faultException.Action);  
  9. }  
  10. } 

 

而在该接口的HandleError()方法中,则可以进行WCF异常处理,例如记录日志。

要使得错误处理扩展生效,还需要向服务通道安装错误处理扩展。方法是让服务类实现System.ServiceModel.Description.IServiceBehavior接口:

  1. public class DocumentsExplorerService : 
    IDocumentsExplorerService,IErrorHandler,IServiceBehavior,IDisposable  
  2. {…} 

 

然后在ApplyDispatchBehavior()方法中安装错误处理扩展:

  1. public void ApplyDispatchBehavior(ServiceDescription 
    serviceDescription, ServiceHostBase serviceHostBase)  
  2. {  
  3. foreach (ChannelDispatcher dispatcher in serviceHostBase.
    ChannelDispatchers)  
  4. {  
  5. dispatcher.ErrorHandlers.Add(this);  
  6. }  
  7. } 

 

通过这样的处理,即使服务抛出的异常为DirectoryNotFoundException异常,并且在服务契约中没有通过FaultContract特性指定该异常,客户端同样能够获得WCF异常处理的错误信息,且该异常不会导致通道发生错误,客户端可以继续调用服务代理对象的操作。

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...