WCF学习之旅—WCF中传统的异常处理(十六)

WCF学习之旅—基于ServiceDebug的异常处理(十七)

三、基于Fault Contract 的异常处理

第二个示例是通过定制ServiceDebug来获取服务端的异常,但是这种方式只能用于Debug阶段。在我们的WCF应用发布之后,这种获取异常的方式无法在我们的工作环境中使用。我们必须找到一种异常处理方式可以在客户端获取相应的异常提示信息。那就是我们接下来要介绍的基于FaultContract的解决方案。我们知道WCF采用一种基于 Contract,Contract定义了进行交互的双方进行消息交换所遵循的准则和规范。Service Contract定义了包含了所有Operation的Service的接口,Data Contract定义了交互的数据的结构,而FaultContract实际上定义需要再双方之间进行交互的了异常、错误的表示。现在我们来学习如何使用基于FaultContract的异常处理。

我们首先来定义一个表示Fault的类:SQLError。考虑到这个类需要在Service 和Client使用,我把它定义在SCF.Contracts中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks; namespace SCF.Contracts
{[DataContract]public class SQLError{private string _operation;private string _errorMessage;public SQLError(string operation, string errorMessage){this._operation = operation;this._errorMessage = errorMessage;}[DataMember]public string Operation{get { return _operation; }set { _operation = value; }} [DataMember]public string ErrorMessage{get { return _errorMessage; }set { _errorMessage = value; }}}}

如果你出现如下图的错误信息,请引用一下System.Runtime.Serialization.dll。

在SQLError中定义了两个成员:表示出 错操作的Operation和出错信息的ErrorMessage。由于该类的对象需要在终结点之间传递,所以必须是可序列化的,在WCF中, 我们一般用两个不同的Serializer实现Object和XML的Serialization和 Deserialization:Datacontract Serializer和XML Serializer。而对于Fault,只能使用前者。

定义了SQLError,我们需要通过特性FaultContract将其添加到EditBook方法上面,我们把IBookService接口修改成如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;namespace SCF.Contracts
{// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IBookService”。
[ServiceContract]public interface IBookService{
[OperationContract]string GetBook(string Id);[OperationContract]string AddBook(string book);[OperationContract][FaultContract(typeof(SQLError))]string EditBook(string book);[OperationContract]string Search(string Category, string searchString);}
}

我们在EditBook上运用了 FaultContract,并指定了封装了Fault对应的类型,那么最终这个基于SQLError类型的FaultContract会被写入 Service Description中,客户端通过获取该Service Description(一般是获取WSDL),它就被识别它,就会将从接收到的Soap中对该Fault的XML Mapping到具体的SQLError类型。

接着我们在服务端的出错处理中抛出Exception的方式植入这个SQLError对象:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Data.Entity;
using SCF.Contracts;
using SCF.Model;
using SCF.Common;namespace SCF.WcfService
{// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“BookService”。// 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 BookService.svc 或 BookService.svc.cs,然后开始调试。public class BookService : IBookService{Entities db = new Entities();public string AddBook(string mbook){try{Books book = XMLHelper.DeSerializer<Books>(mbook);db.Books.Add(book);db.SaveChanges();}catch (Exception ex){return ex.Message;}                    return "true";        }public string EditBook(string mbook){try{Books book = XMLHelper.DeSerializer<Books>(mbook);db.Entry(book).State = EntityState.Added;db.SaveChanges();}catch (Exception ex){//return ex.Message;               SQLError error = new SQLError("更新数据库操作", ex.Message);string reason = string.Empty;if (ex.InnerException != null){reason = string.Format("{0}。{1}"ex.Message, ex.InnerException.Message);}else reason = ex.Message;throw new FaultException<SQLError>(error, new FaultReason(reason), new FaultCode("Edit"));}return "true";} public string GetBook(string Id){        int bookId = Convert.ToInt32(Id);Books book= db.Books.Find(bookId);string xml=XMLHelper.ToXML<Books>(book);return xml;//throw new NotImplementedException();
        }public string Search(string Category, string searchString){var cateLst = new List<string>();var cateQry = from d in db.Booksorderby d.Categoryselect d.Category;cateLst.AddRange(cateQry.Distinct());      var books = from m in db.Booksselect m;if (!String.IsNullOrEmpty(searchString)){books = books.Where(s => s.Name.Contains(searchString));}List<Books> list = null;if (string.IsNullOrEmpty(Category)){list = books.ToList<Books>();}else{list = books.Where(x => x.Category == Category).ToList<Books>();}return XMLHelper.ToXML<List<Books>>(list);}}}

在catch中,抛出FaultException<SQLError> Exception,并指定具体的SQLError对象,以及一个FaultCode(一般指明出错的来源)和FaultReason(出错的原因)。我们现在先不修改客户端的异常处理的相关代码,先运行Hosting,看看WSDL中什么特别之处,如下图:


    通 过上图,我们可以看到,在EditBook方法的WSDL定义了中多了一些节点。

弄清楚了Fault在WSDL中表示后,我们来修改我们客户端的代码,来有效地进行异常处理:

using SCF.Contracts;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SCF.Model;
using SCF.Common;namespace WinClient
{public partial class FrmBook : Form{public FrmBook(){InitializeComponent();}private void ShowBook(){Books book = XMLHelper.DeSerializer<Books>(textBoxMsg.Text);txtBookId.Text = book.BookID.ToString();txtAuthorID.Text = book.AuthorID.ToString();textBoxName.Text = book.Name;textBoxCategory.Text = book.Category.ToString();textBoxPrice.Text = book.Price.ToString();textBoxRating.Text = book.Rating.ToString();textBoxNumberofcopies.Text = book.Numberofcopies.ToString();dateTimePickerPublishDate.Text = book.PublishDate.ToString();}private void btnSearch_Click(object sender, EventArgs e){BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();textBoxMsg.Text = bookSvrClient.Search(string.Empty, string.Empty);List<Books> books = XMLHelper.DeSerializer<List<Books>>(textBoxMsg.Text);gridBooks.DataSource = books;}private void buttonSave_Click(object sender, EventArgs e){try{using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService")){IBookService proxy = channelFactory.CreateChannel();using (proxy as IDisposable){if (string.IsNullOrEmpty(txtBookId.Text)){textBoxMsg.Text = proxy.AddBook(GetBookInfo());}elsetextBoxMsg.Text = proxy.EditBook(GetBookInfo());}}}catch (FaultException<SQLError> ex){SQLError error = ex.Detail;textBoxMsg.Text = string.Format("抛出一个服务端错误。\r\n\t错误代码:{0}\n\t错误原因:{1}\r\n\t操作:{2}\r\n\t错误信息:{3}", ex.Code, ex.Reason, error.Operation, error.ErrorMessage);}catch (Exception ex){if (ex.InnerException != null){textBoxMsg.Text = ex.Message + ex.InnerException.Message;}elsetextBoxMsg.Text = ex.Message;}}public String GetBookInfo(){Books book = new Books();book.AuthorID = NumberHelper.ToInt(txtAuthorID.Text);book.BookID = NumberHelper.ToInt(txtBookId.Text);book.Category = textBoxCategory.Text;book.Name = textBoxName.Text;book.Numberofcopies = NumberHelper.ToInt(textBoxNumberofcopies.Text);book.Price = NumberHelper.ToDecimal(textBoxPrice.Text);book.PublishDate = dateTimePickerPublishDate.Value;book.Rating = textBoxRating.Text;textBoxMsg.Text = XMLHelper.ToXML<Books>(book);return textBoxMsg.Text;}}
}

执行“保存”操作之后,服务端抛出了如下错误信息:

WCF学习之旅—基于Fault Contract 的异常处理(十八)相关推荐

  1. WCF学习之旅—实现支持REST客户端应用(二十四)

    WCF学习之旅-实现REST服务(二十二) WCF学习之旅-实现支持REST服务端应用(二十三) 在上二篇文章中简单介绍了一下RestFul与WCF支持RestFul所提供的方法,及创建一个支持RES ...

  2. WCF学习之旅—WCF服务的WAS寄宿(十二)

    上接    WCF学习之旅-WCF服务部署到IIS7.5(九) WCF学习之旅-WCF服务部署到应用程序(十) WCF学习之旅-WCF服务的Windows 服务程序寄宿(十一) 八.WAS宿主 IIS ...

  3. WCF学习之旅—第三个示例之四(三十)

           上接WCF学习之旅-第三个示例之一(二十七)               WCF学习之旅-第三个示例之二(二十八)              WCF学习之旅-第三个示例之三(二十九)   ...

  4. WCF学习之旅(一)---Hello World.

    WCF学习之旅(一)---Hello World. 看了一些关于WCF的资料,从实例入手.记录自己学习WCF的过程. 从最简单的Hello World入门. 下图是我的solution及项目. 项目名 ...

  5. WCF学习之旅—第三个示例之二(二十八)

    上接WCF学习之旅-第三个示例之一(二十七) 五.在项目BookMgr.Model创建实体类数据 第一步,安装Entity Framework 1)  使用NuGet下载最新版的Entity Fram ...

  6. 【Vue学习】—Vue UI组件库(二十八)

    [Vue学习]-Vue UI组件库(二十八) 一.移动端常用的UI组件库 二.PC端常用的UI组件库 三.具体使用自行查看文档,这里就不做概述了

  7. WCF学习之旅—WCF第二个示例(七)

    三.创建客户端应用程序 若要创建客户端应用程序,你将另外添加一个项目,添加对该项目的服务引用,配置数据源,并创建一个用户界面以显示服务中的数据. 在第一个步骤中,你将 Windows 窗体项目添加到解 ...

  8. WCF学习之旅—WCF寄宿前的准备(八)

    一.WCF服务应用程序与WCF服务库 我们在平时开发的过程中常用的项目类型有"WCF 服务应用程序"和"WCF服务库". WCF服务应用程序,是一个可以执行的程 ...

  9. WCF学习之旅—WCF概述(四)

    一.WCF概述 1) 什么是WCF? Windows Communication Foundation (WCF) 是用于构建面向服务的应用程序的框架.借助 WCF,可以将数据作为异步消息从一个服务终 ...

最新文章

  1. Windows 根据进程名杀死进程 kill
  2. 活动目录系列之一:基本概念
  3. DataTable 去重合并
  4. 【暂时完结】Prescan学习笔记
  5. php对接海康视频教程_海康安防管理平台Web视频对接
  6. 打表法判断素数 c语言,素数打表(4种方法)
  7. c语言 大写字母转换为小写字母后的第五个,将大写字母转换为对应小写字母之后的第5字母;若小写字母为v~z,使小写字母的值减21。...
  8. 基于LabView开发的串口助手
  9. 自定义设置HTTP响应头
  10. ARM Linux下的phys_to_virt/virt_to_phys函数
  11. Cherry机械键盘、开发板、无线鼠标等100份好礼,回帖就送!
  12. caffe ssd 测试demo,检测单张图片
  13. 尚硅谷-谷粒商城-电商项目-秒杀系统-笔记
  14. 第十一届河南省ACM C题山区修路
  15. C++ 二维vector排序(sort用法)
  16. go连接数据库(简单的查询学习)
  17. hive静态分区,动态分区 -夜幕思年华
  18. SQL-正序倒序查询
  19. ​一生e本B11学习笔记本电脑即将上市?具体几号?
  20. 从零开始的前端学习路线

热门文章

  1. ACM_无聊者序列(斐波那契数列大数取余(同余)+规律)
  2. VIM - 每行前或者每行后增加相同的字符串
  3. C语言程序设计50例(三)(经典收藏)
  4. semaphore, completion 和 wait_queue
  5. Makefile常用万能模板(包括静态链接库、动态链接库、可执行文件)
  6. 聊聊IO多路复用之select、poll、epoll详解
  7. 训练MNIST数据集模型
  8. 利用Memcache解决数据库高并发访问的瓶颈问题
  9. 【synchronized底层原理之4】锁的升级过程及比较
  10. find命令以及管道的简单使用技巧