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

简介:

上篇中,我详细介绍了如何通过自定义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月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
287 12
|
6月前
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
289 3
|
2月前
|
人工智能 运维 负载均衡
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
87 0
|
2月前
|
人工智能 自然语言处理 分布式计算
AI 驱动传统 Java 应用集成的关键技术与实战应用指南
本文探讨了如何将AI技术与传统Java应用集成,助力企业实现数字化转型。内容涵盖DJL、Deeplearning4j等主流AI框架选择,技术融合方案,模型部署策略,以及智能客服、财务审核、设备诊断等实战应用案例,全面解析Java系统如何通过AI实现智能化升级与效率提升。
269 0
|
4月前
|
机器学习/深度学习 数据采集 存储
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
本文探讨了朴素贝叶斯算法在处理混合数据类型中的应用,通过投票和堆叠集成方法构建分类框架。实验基于电信客户流失数据集,验证了该方法的有效性。文章详细分析了算法的数学理论基础、条件独立性假设及参数估计方法,并针对二元、类别、多项式和高斯分布特征设计专门化流水线。实验结果表明,集成学习显著提升了分类性能,但也存在特征分类自动化程度低和计算开销大的局限性。作者还探讨了特征工程、深度学习等替代方案,为未来研究提供了方向。(239字)
176 5
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
|
4月前
|
缓存 前端开发 定位技术
通义灵码2.5智能体模式实战———集成高德MCP 10分钟生成周边服务地图应用
通义灵码2.5智能体模式结合高德MCP服务,实现快速构建周边服务地图应用。通过自然语言需求输入,智能体自动分解任务并生成完整代码,涵盖前端界面、API集成与数据处理,10分钟内即可完成传统开发需数小时的工作,大幅提升开发效率。
278 0
|
7月前
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
392 27
|
7月前
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
前端开发
WCF更新服务引用报错的原因之一
WCF更新服务引用报错的原因之一
|
C# 数据安全/隐私保护
c#如何创建WCF服务到发布(SqlServer版已经验证)
c#如何创建WCF服务到发布(SqlServer版已经验证)
136 0

推荐镜像

更多
  • DNS