Enterprise Library深入解析与灵活应用(8):WCF与Exception Handling AppBlock集成[下]

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

上篇中,我详细介绍了如何通过自定义ClientMessageInspector和ErrorHandler,实现WCF与微软企业库中的Exception Handling Application Block(EHAB)之间的集成。这个方案的基本思路就是:当异常从服务端抛出,利用EHAB针对某个配置好的异常处理策略进行处理;然后将处理有的异常通过ServiceExceptionDetail对象进行封装,最后序列化置于Fault消息,最终被返回给客户端;客户端接收到该Fault消息后,提取并创建ServiceExceptionDetail对象,并通过反射重建异常;最后将异常抛出,使客户端可以根据客户端配置的异常处理策略对该异常进行进一步的处理。(Source Code从这里下载)

为了实现WCF对ServiceExceptionDetail对象的序列化和反序列化,我们必须通过FaultContractAttribute特性将类型定义成错误契约,相应的形式如下面的代码所示。在一般的情况下,如果你定义的服务是为他人所用,比如第三方服务消费者,该错误契约的定义是必须的,因为相应的错误明细类型需要通过元数据的形式发布出来,指导客户端如何对接收到的消息进行反序列化。但是,如果服务仅供你自己的应用所用,那么你可以在运行时动态地添加相应的错误描述,从而避免在服务契约的每一个服务操作方法上应用这么一个FaultContractAttribute

   1: [ServiceContract(Namespace = "http://www.artech.com/")]
   2: public interface ICalculator
   3: {
   4:     [OperationContract]
   5:     [ExceptionHandlingBehavior("myExceptionPolicy")]
   6:     [FaultContract(typeof(ServiceExceptionDetail), Action = "http://www.artech.com/fault")]
   7:     int Divide(int x, int y);
   8: }

我们应用在操作方法上面的FaultContractAttribute特性,最终会转换成操作描述(OperationDescription)的错误描述(FaultDescription),如果我们在运行时能够为所有的操作描述添加相应的错误描述,就能避免在每个服务操作上面应用相同的FaultContractAttribute特性。不过,为了服务的重用,我不介意这样偷懒,所以这种方案仅仅作为研究、学习之用。

一、通过自定义ServiceHost的方式动态添加错误描述(服务端)

首先需要在服务端为每一个服务操作添加基于ServiceExceptionDetail的错误描述,这可以通过自定ServiceHost来实现。由于服务描述需要在ServiceHost开启之前生成方才有效(具体的原因,相对比较复杂,大家可以在《WCF技术剖析(卷1)》第7章关于服务寄宿的部分找到答案),所以我们将相关的逻辑定义在OnOpening方法之中。在下面的代码中,我定义了这样一个简单的ServiceHost:ExceptionHandlingServiceHost。

   1: using System;
   2: using System.ServiceModel;
   3: using System.ServiceModel.Activation;
   4: using System.ServiceModel.Description;
   5:  
   6: namespace Artech.EnterLibIntegration.WcfExtensions
   7: {
   8:     public class ExceptionHandlingServiceHost : ServiceHost
   9:     {
  10:         public ExceptionHandlingServiceHost(Type t, params Uri[] baseAddresses)
  11:             : base(t, baseAddresses)
  12:         { }
  13:  
  14:         protected override void OnOpening()
  15:         {
  16:             base.OnOpening();
  17:             foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
  18:             {
  19:                 foreach (OperationDescription operation in endpoint.Contract.Operations)
  20:                 { 
  21:                     FaultDescription faultDescription = new FaultDescription(ServiceExceptionDetail.FaultAction);
  22:                     faultDescription.DetailType = typeof(ServiceExceptionDetail);
  23:                     operation.Faults.Add(faultDescription);
  24:                 }
  25:             }
  26:         }
  27:     }
  28: }

逻辑相对比较简单:遍历所有终结点(ServiceEndpoint),为每一个终结点的契约(ContractDescription)的每一个操作(OperationDescription)添加错误明细类型为ServiceExceptionDetail的错误描述(FaultDescription),并指定预定义的Action。

对于自定义的ServiceHost,可以直接用于不需要.svc文件进行访问的寄宿场景,也就是说对于除了IIS和WAS的服务寄宿,可以直接采用自定义的ServiceHost。服务需要在基于IIS和WAS的寄宿方式中采用自定义的ServiceHost,还需要为之创建相应的ServiceHostFactory(关于ServiceHostFactory作用和用法,同样可以参阅《WCF技术剖析(卷1)》第7章)。下面,我们为ExceptionHandlingServiceHost定义了一个简单的ServiceHostFactory:ExceptionHandlingServiceHostFactory。

   1: using System;
   2: using System.ServiceModel;
   3: using System.ServiceModel.Activation;
   4: using System.ServiceModel.Description;
   5:  
   6: namespace Artech.EnterLibIntegration.WcfExtensions
   7: {
   8:     public class ExceptionHandlingServiceHostFactory : ServiceHostFactory
   9:     {
  10:         protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
  11:         {
  12:             return new ExceptionHandlingServiceHost(serviceType, baseAddresses);
  13:         }
  14:     }
  15: }

二、通过自定义ChannelFactory<TChanel>的方式动态添加错误描述(客户端)

服务端需要为每一个操作添加基于ServiceExceptionDetail的错误描述,以便实现对该对象的序列化;同理,客户端同样需要这样一个错误描述,以实现对该对象的反序列化。我们可以将这样的功能通过一个自定义ChannelFactory<TChannel>来实现。下面定义的ExceptionHandlingChannelFactory就是这样一个自定的ChannelFactory<TChannel>。对错误描述的添加实现在重写的CreateDescription方法中:

   1: using System.ServiceModel;
   2: using System.ServiceModel.Description;
   3:  
   4: namespace Artech.EnterLibIntegration.WcfExtensions
   5: {
   6:     public class ExceptionHandlingChannelFactory<TChannel>:ChannelFactory<TChannel>
   7:     {
   8:         public ExceptionHandlingChannelFactory(string endpointConfigurationName)
   9:             : base(endpointConfigurationName)
  10:         { }
  11:  
  12:         protected override ServiceEndpoint CreateDescription()
  13:         {  
  14:             ServiceEndpoint serviceEndpoint = base.CreateDescription();
  15:             foreach (OperationDescription operation in serviceEndpoint.Contract.Operations)
  16:             {
  17:                 FaultDescription faultDescription = new FaultDescription(ServiceExceptionDetail.FaultAction);
  18:                 faultDescription.DetailType = typeof(ServiceExceptionDetail);
  19:                 operation.Faults.Add(faultDescription);
  20:             }
  21:  
  22:             return serviceEndpoint;
  23:         }
  24:     }
  25: }

三、实例演示

那么,对其我们给出的例子,我们就要使用我们上面创建的这两个组件了。首先,有了这两个组件的帮助,在服务契约中,我们再也不需要在繁琐地为每一个服务操作定义相同的FaultContractAttribute特性了。于是我们先将其拿掉。

   1: [ServiceContract(Namespace = "http://www.artech.com/")]
   2: public interface ICalculator
   3: {
   4:     [OperationContract]
   5:     [ExceptionHandlingBehavior("myExceptionPolicy")]
   6:     int Divide(int x, int y);
   7: }   

然后,再进行服务寄宿的时候,直接利用我们定义的ExceptionHandlingServiceHost就可以了。

   1: using System;
   2: using Artech.EnterLibIntegration.WcfExtensions;
   3: using Artech.WcfServices.Services;
   4: namespace Artech.WcfServices.Hosting
   5: {
   6:     public class Program
   7:     {
   8:         static void Main(string[] args)
   9:         {
  10:             using (ExceptionHandlingServiceHost host = new ExceptionHandlingServiceHost(typeof(CalculatorService)))
  11:             {
  12:  
  13:                 host.Open();
  14:                 Console.Read();
  15:             }
  16:         }
  17:     }
  18: }

而客户端,我们可以借助于我们定义的ExceptionHandlingChannelFactory<TChannel>实现对服务代理的创建。

   1: using System;
   2: using Artech.EnterLibIntegration.WcfExtensions;
   3: using Artech.WcfServices.Contracts;
   4: namespace Artech.WcfServices.Clients
   5: {
   6:     class Program
   7:     {
   8:         static void Main(string[] args)
   9:         {
  10:             using (ExceptionHandlingChannelFactory<ICalculator> channelFactory = new ExceptionHandlingChannelFactory<ICalculator>(
  11:                "calculatorservice"))
  12:             {
  13:                 ICalculator calculator = channelFactory.CreateChannel();
  14:                 using (calculator as IDisposable)
  15:                 {
  16:                     try
  17:                     {
  18:                         int result = calculator.Divide(1, 0);
  19:                     }
  20:                     catch (CalculationException ex)
  21:                     {
  22:                         Console.WriteLine(ex.Message);
  23:                         Console.WriteLine("InnerException");
  24:                         Console.WriteLine("\tType:{0}", ex.InnerException.GetType());
  25:                         Console.WriteLine("\tMessage:{0}", ex.InnerException.Message);
  26:                     }
  27:                 }
  28:             }
  29:  
  30:             Console.Read();
  31:         }
  32:     }
  33: }

这样我们同样可以得到与上篇一样的执行结果:

计算错误
InnerException
        Type:System.DivideByZeroException
        Message:试图除以零.

作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
1月前
|
前端开发 JavaScript UED
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
通过在Django项目中集成Channels和WebSocket,我们能够为前后端分离的应用添加实时通信功能,实现诸如在线聊天、实时数据更新等交互式场景。这不仅增强了应用的功能性,也提升了用户体验。随着实时Web应用的日益普及,掌握Django Channels和WebSocket的集成将为开发者开启新的可能性,推动Web应用的发展迈向更高层次的实时性和交互性。
77 1
|
1月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
2月前
|
机器学习/深度学习 人工智能 搜索推荐
如何让你的Uno Platform应用秒变AI大神?从零开始,轻松集成机器学习功能,让应用智能起来,用户惊呼太神奇!
【9月更文挑战第8天】随着技术的发展,人工智能与机器学习已融入日常生活,特别是在移动应用开发中。Uno Platform 是一个强大的框架,支持使用 C# 和 XAML 开发跨平台应用(涵盖 Windows、macOS、iOS、Android 和 Web)。本文探讨如何在 Uno Platform 中集成机器学习功能,通过示例代码展示从模型选择、训练到应用集成的全过程,并介绍如何利用 Onnx Runtime 等库实现在 Uno 平台上的模型运行,最终提升应用智能化水平和用户体验。
56 1
|
2月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
150 0
|
3月前
|
存储 C# 关系型数据库
“云端融合:WPF应用无缝对接Azure与AWS——从Blob存储到RDS数据库,全面解析跨平台云服务集成的最佳实践”
【8月更文挑战第31天】本文探讨了如何将Windows Presentation Foundation(WPF)应用与Microsoft Azure和Amazon Web Services(AWS)两大主流云平台无缝集成。通过具体示例代码展示了如何利用Azure Blob Storage存储非结构化数据、Azure Cosmos DB进行分布式数据库操作;同时介绍了如何借助Amazon S3实现大规模数据存储及通过Amazon RDS简化数据库管理。这不仅提升了WPF应用的可扩展性和可用性,还降低了基础设施成本。
83 0
|
3月前
|
开发者 C# UED
WPF与多媒体:解锁音频视频播放新姿势——从界面设计到代码实践,全方位教你如何在WPF应用中集成流畅的多媒体功能
【8月更文挑战第31天】本文以随笔形式介绍了如何在WPF应用中集成音频和视频播放功能。通过使用MediaElement控件,开发者能轻松创建多媒体应用程序。文章详细展示了从创建WPF项目到设计UI及实现媒体控制逻辑的过程,并提供了完整的示例代码。此外,还介绍了如何添加进度条等额外功能以增强用户体验。希望本文能为WPF开发者提供实用的技术指导与灵感。
147 0
|
3月前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
64 0
|
3月前
|
测试技术 Java Spring
Spring 框架中的测试之道:揭秘单元测试与集成测试的双重保障,你的应用真的安全了吗?
【8月更文挑战第31天】本文以问答形式深入探讨了Spring框架中的测试策略,包括单元测试与集成测试的有效编写方法,及其对提升代码质量和可靠性的重要性。通过具体示例,展示了如何使用`@MockBean`、`@SpringBootTest`等注解来进行服务和控制器的测试,同时介绍了Spring Boot提供的测试工具,如`@DataJpaTest`,以简化数据库测试流程。合理运用这些测试策略和工具,将助力开发者构建更为稳健的软件系统。
59 0
|
3月前
|
开发者 前端开发 开发框架
JSF与移动应用,开启全新交互体验!让你的Web应用轻松征服移动设备,让用户爱不释手!
【8月更文挑战第31天】在现代Web应用开发中,移动设备的普及使得构建移动友好的应用变得至关重要。尽管JSF(JavaServer Faces)主要用于Web应用开发,但结合Bootstrap等前端框架,也能实现优秀的移动交互体验。本文探讨如何在JSF应用中实现移动友好性,并通过示例代码展示具体实现方法。使用Bootstrap的响应式布局和组件可以确保JSF页面在移动设备上自适应,并提供友好的表单输入和提交体验。尽管JSF存在组件库较小和学习成本较高等局限性,但合理利用其特性仍能显著提升用户体验。通过不断学习和实践,开发者可以更好地掌握JSF应用的移动友好性,为Web应用开发贡献力量。
52 0
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
81 0

热门文章

最新文章

推荐镜像

更多