WCF学习之旅—基于Fault Contract 的异常处理(十八)
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.Books
orderby d.Category
select d.Category;
cateLst.AddRange(cateQry.Distinct()); var books = from m in db.Books
select 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());
}
else
textBoxMsg.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;
}
else
textBoxMsg.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 的异常处理(十八)的更多相关文章
- WCF学习之旅—基于ServiceDebug的异常处理(十七)
WCF学习之旅—WCF中传统的异常处理(十六) 二.基于ServiceDebug的异常处理 从前面的示例中,可以看到客户端捕获了异常,这是我们处理异常的前提.为了有利于我们进行有效的调试,WCF提供了 ...
- WCF学习之旅—HTTP双工模式(二十)
WCF学习之旅—请求与答复模式和单向模式(十九) 四.HTTP双工模式 双工模式建立在上文所实现的两种模式的基础之上,实现客户端与服务端相互调用:前面介绍的两种方法只是在客户端调用服务端的方法,然后服 ...
- WCF学习之旅—实现REST服务(二十二)
一.什么是REST 表述性状态转移(Representational State Transfer,REST),不是一种标准,而是一种软件架构风格. 基于REST的服务与基于SOAP的服务相比,性能. ...
- WCF学习之旅—TCP双工模式(二十一)
WCF学习之旅—请求与答复模式和单向模式(十九) WCF学习之旅—HTTP双工模式(二十) 五.TCP双工模式 上一篇文章中我们学习了HTTP的双工模式,我们今天就学习一下TCP的双工模式. 在一个基 ...
- WCF学习之旅—实现支持REST服务端应用(二十三)
在上一篇(WCF学习之旅—实现REST服务(二十二))文章中简单介绍了一下RestFul与WCF支持RestFul所提供的方法,本文讲解一下如何创建一个支持REST的WCF服务端程序. 四.在WCF中 ...
- WCF学习之旅—实现支持REST客户端应用(二十四)
WCF学习之旅—实现REST服务(二十二) WCF学习之旅—实现支持REST服务端应用(二十三) 在上二篇文章中简单介绍了一下RestFul与WCF支持RestFul所提供的方法,及创建一个支持RES ...
- WCF学习之旅—WCF服务部署到IIS7.5(九)
上接 WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...
- WCF学习之旅—WCF服务的批量寄宿(十三)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一) WCF学习之旅—WCF ...
- WCF学习之旅—TcpTrace工具(二十六)
止文(WCF学习之旅—TcpTrace工具(二十五))介绍了关于TcpTrance的一种使用方式,接下来介绍第二种使用方式. 三.通过ListenUri实现基于tcpTracer的消息路由 对于路由的 ...
随机推荐
- 看完SQL Server 2014 Q/A答疑集锦:想不升级都难!
看完SQL Server 2014 Q/A答疑集锦:想不升级都难! 转载自:http://mp.weixin.qq.com/s/5rZCgnMKmJqeC7hbe4CZ_g 本期嘉宾为微软技术中心技术 ...
- jQuery学习之路(1)-选择器
▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...
- Android 剪贴板详解
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Clipboard 如本文有助于你理解 Android 剪贴板,不妨给我一个 Star.对于码农而言, ...
- 香蕉云APP,2016下半年开发日记
2016-6-17 数据库设计不应该过多依赖范式,适度的冗余可以加快搜索速度,在服务器的配置还可以的情况下,可以采用冗余来解决查找慢的问题.还一个是要选择好数据库引擎,例如 InnoDB 和 myi ...
- 讓TQ2440也用上設備樹(1)
作者:彭東林 郵箱:pengdonglin137@163.com QQ:405728433 開發板 TQ2440 + 64MB 內存 + 256MB Nand 軟件 Linux: Linux-4.9 ...
- 灵魂宝石 bzoj 2663
灵魂宝石(1s 128MB)soulgem [问题描述] "作为你们本体的灵魂,为了能够更好的运用魔法,被赋予了既小巧又安全的外形" 我们知道,魔法少女的生命被存放于一个称为灵魂宝 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- Redis配置文件redis.conf
1.地址 2.Units单位 1 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit 2 对大小写不敏感 3.includes包含
- Linux基础介绍【第一篇】
Linux简介 什么是操作系统? 操作系统,英文名称Operating System,简称OS,是计算机系统中必不可少的基础系统软件,它是应用程序运行以及用户操作必备的基础环境支撑,是计算机系统的核心 ...
- mysql 大表拆分成csv导出
最近公司有一个几千万行的大表需要按照城市的id字段拆分成不同的csv文件. 写了一个自动化的shell脚本 在/home/hdh 下面 linux-xud0:/home/hdh # lltotal 1 ...