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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 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
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
6天前
|
存储 人工智能 NoSQL
Airweave:快速集成应用数据打造AI知识库的开源平台,支持多源整合和自动同步数据
Airweave 是一个开源工具,能够将应用程序的数据同步到图数据库和向量数据库中,实现智能代理检索。它支持无代码集成、多租户支持和自动同步等功能。
66 14
|
11天前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
141 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
26天前
|
机器人 应用服务中间件 API
轻松集成私有化部署Dify文本生成型应用
Dify 是一款开源的大语言模型应用开发平台,融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者能快速搭建生产级生成式 AI 应用。通过阿里云计算巢,用户可以一键部署 Dify 社区版,享受独享的计算和网络资源,并无代码完成钉钉、企业微信等平台的应用集成。本文将详细介绍如何部署 Dify 并将其集成到钉钉群聊机器人和企业微信中,帮助您轻松实现 AI 应用的定义与数据运营,提升工作效率。
轻松集成私有化部署Dify文本生成型应用
|
1月前
|
人工智能 数据可视化 开发者
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
FlowiseAI 是一款开源的低代码工具,通过拖拽可视化组件,用户可以快速构建自定义的 LLM 应用程序,支持多模型集成和记忆功能。
117 14
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
|
3月前
|
消息中间件 Java Kafka
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
87 1
|
3月前
|
机器学习/深度学习 Python
堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能
本文深入探讨了堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能。文章详细介绍了堆叠的实现步骤,包括数据准备、基础模型训练、新训练集构建及元学习器训练,并讨论了其优缺点。
165 3
|
1月前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
53 0
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析

热门文章

最新文章

推荐镜像

更多