WCF学习之旅—WCF中传统的异常处理(十六)
WCF中的异常处理
在软件开发过程中,不可能没有异常的出现,所以在开发过程中,对不可预知的异常进行解决时,异常处理显得尤为重要。对于一般的.NET系统来说,我们简单地借助try/catch可以很容易地实现这一功能。但是对于 一个分布式的环境来说,异常处理就没有那么简单了。按照面向服务的原则,我们把一些可复用的业务逻辑以服务的形式实现,各个服务处于一个自治的环境中,一个服务需要和另一个服务进行交互,只需要获得该服务的描述(Description)就可以了(比如 WSDL,Schema和Strategy)。借助标准的、平台无关的通信构架,各个服务之间通过标准的Soap Message进行交互。Service Description、Standard Communication Infrastructure、Soap Message based Communication促使各服务以松耦合的方式结合在一起。但是由于各个服务是自治的,如果一个服务调用另一个服务,在服务提供方抛出的Exception必须被封装在Soap Message中,方能被处于另一方的服务的使用者获得、从而进行合理的处理。下面我们结合一个简单的示例来简单地介绍一下我们可以通过哪些方式在WCF服务应用程序中进行异常处理。
一、传统的异常处理
我们还是使用上面文章中使用过的书籍管理示例。如下图。

1. SCF.Contracts
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]
void DoWork(); [OperationContract]
string GetBook(string Id); [OperationContract]
string AddBook(string book); [OperationContract]
string EditBook(string book); [OperationContract]
string Search(string Category, string searchString); } }
2. SCF.WcfService
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 void DoWork()
{ } 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;
throw ex;
}
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>();
//return XMLHelper.ToXML<List<Books>>(list);
}
else
{
list = books.Where(x => x.Category == Category).ToList<Books>();
// return XMLHelper.ToXML<IQueryable<Books>>(books.Where(x => x.Category == Category));
}
return XMLHelper.ToXML<List<Books>>(list);
} } }
注:在编辑书籍信息时,会抛出一个DbUpdateException信息。我在数据库中设了一个唯一索引,不能插入重复值
3. Service Hosting
配置文件信息如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework> <system.serviceModel> <behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8888/BookService/metadata" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors> </behaviors> <services>
<service behaviorConfiguration="metadataBehavior" name="SCF.WcfService.BookService">
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
contract="SCF.Contracts.IBookService" />
</service>
</services>
</system.serviceModel> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup> <connectionStrings>
<add name="TestEntities" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Test;Integrated Security=SSPI"
providerName="System.Data.SqlClient" />
<add name="Entities" connectionString="metadata=res://*/BookModel.csdl|res://*/BookModel.ssdl|
res://*/BookModel.msl;provider=System.Data.SqlClient;provider connection string="data source=.\SQLEXPRESS;initial catalog
=Test;integrated security=SSPI;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Host程序代码如下:
using SCF.WcfService;
using SCF.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks; namespace Hosting
{
class Program
{ static void Main(string[] args)
{
try
{
using (ServiceHost host = new ServiceHost(typeof(BookService)))
{
host.Opened += delegate
{
Console.WriteLine("BookService,使用配置文件,按任意键终止服务!");
};
host.Open();
Console.ForegroundColor = ConsoleColor.Yellow;
foreach (ServiceEndpoint se in host.Description.Endpoints)
{
Console.WriteLine("[终结点]: {0}\r\n\t[A-地址]: {1} \r\n\t [B-绑定]: {2} \r\n\t [C-协定]: {3}",
se.Name, se.Address, se.Binding.Name, se.Contract.Name); } Console.Read();
}
}
catch (Exception ex)
{ Console.WriteLine(ex.Message);
} //Console.Read();
}
}
}
4. 客户端代码如下
配置文件信息如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup> <system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBookService" />
<binding name="WSHttpBinding_IBookService1" /> </wsHttpBinding>
<customBinding>
<binding name="listenUriBinding">
<textMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IBookService" contract="SCF.Contracts.IBookService"
name="WSHttpBinding_IBookService">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" /> </identity>
</endpoint>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IBookService1" contract="BookServiceRef.IBookService"
name="WSHttpBinding_IBookService1">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
客户端程序代码如下:
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 btnGetBook_Click(object sender, EventArgs e)
{
Books book = new Books();
BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
if (gridBooks.SelectedRows.Count > )
{
book = gridBooks.SelectedRows[].DataBoundItem as Books; textBoxMsg.Text = bookSvrClient.GetBook(book.BookID.ToString());
ShowBook();
}
else
{
textBoxMsg.Text = "没有选中相应的记录!";
}
} /// <summary>
/// ChannelFactory方式,直接在代码中写配置信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonChannelFactory_Click(object sender, EventArgs e)
{ using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>
(new WSHttpBinding(), "http://127.0.0.1:8888/BookService"))
{
IBookService proxy = channelFactory.CreateChannel();
using (proxy as IDisposable)
{
textBoxMsg.Text = proxy.GetBook("");
ShowBook();
}
} } /// <summary>
/// ChannelFactory配置方式,在配置文件中写配置信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonChannelConfig_Click(object sender, EventArgs e)
{
using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService"))
{
IBookService proxy = channelFactory.CreateChannel();
using (proxy as IDisposable)
{
textBoxMsg.Text = proxy.GetBook("");
ShowBook();
}
}
} 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 btnSearchCategory_Click(object sender, EventArgs e)
{
BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
textBoxMsg.Text = bookSvrClient.Search(txtCategory.Text, 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 (Exception ex) {
throw ex;
} } 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;
} } }
把Service调用放在一个try/catch 程序代码段中,看看Service端抛出的DbUpdateException能否被Catch。
现在我们运行这个程序,看看客户端报错信息如下:
我们发现客户端无法捕捉服务端真正抛出的出错信息,而是一个比较通用的FaultException。错误信息也是很通用的一种,无法有效提供详细的错误信息,以供我们来解决问题。
WCF学习之旅—WCF中传统的异常处理(十六)的更多相关文章
- WCF学习之旅—基于Fault Contract 的异常处理(十八)
WCF学习之旅—WCF中传统的异常处理(十六) WCF学习之旅—基于ServiceDebug的异常处理(十七) 三.基于Fault Contract 的异常处理 第二个示例是通过定制Servic ...
- WCF学习之旅—WCF服务部署到IIS7.5(九)
上接 WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...
- WCF学习之旅—WCF服务部署到应用程序(十)
上接 WCF学习之旅—WCF寄宿前的准备(八) WCF学习之旅—WCF服务部署到IIS7.5(九) 五.控制台应用程序宿主 (1) 在解决方案下新建控制台输出项目 ConsoleHosting.如下 ...
- WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...
- WCF学习之旅—WCF服务的WAS寄宿(十二)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一) 八.WAS宿主 IIS ...
- WCF学习之旅—WCF服务的批量寄宿(十三)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一) WCF学习之旅—WCF ...
- WCF学习之旅—WCF第二个示例(五)
二.WCF服务端应用程序 第一步,创建WCF服务应用程序项目 打开Visual Studio 2015,在菜单上点击文件—>新建—>项目—>WCF服务应用程序.在弹出界面的“名称”对 ...
- WCF学习之旅—WCF第二个示例(七)
三.创建客户端应用程序 若要创建客户端应用程序,你将另外添加一个项目,添加对该项目的服务引用,配置数据源,并创建一个用户界面以显示服务中的数据. 在第一个步骤中,你将 Windows 窗体项目添加到解 ...
- WCF学习之旅—WCF第二个示例(六)
第五步,创建数据服务 在“解决方案资源管理器”中,使用鼠标左键选中“SCF.WcfService”项目,然后在菜单栏上,依次选择“项目”.“添加新项”. 在“添加新项”对话框中,选择“Web”节点,然 ...
- WCF学习之旅—HTTP双工模式(二十)
WCF学习之旅—请求与答复模式和单向模式(十九) 四.HTTP双工模式 双工模式建立在上文所实现的两种模式的基础之上,实现客户端与服务端相互调用:前面介绍的两种方法只是在客户端调用服务端的方法,然后服 ...
随机推荐
- git-简单流程(学习笔记)
这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...
- ABP文档 - 通知系统
文档目录 本节内容: 简介 发送模式 通知类型 通知数据 通知重要性 关于通知持久化 订阅通知 发布通知 用户通知管理器 实时通知 客户端 通知存储 通知定义 简介 通知用来告知用户系统里特定的事件发 ...
- 基于SignalR实现B/S系统对windows服务运行状态的监测
通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...
- Axure 8.0.0.3312可用注册码
用户名:aaa 注册码:2GQrt5XHYY7SBK/4b22Gm4Dh8alaR0/0k3gEN5h7FkVPIn8oG3uphlOeytIajxGU 用户名:axureuser 序列号:8wFfI ...
- 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)
建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...
- ajax请求和aspx返回数据
ajax请求: $(function () { $.ajax({ url: "index.aspx?method=send", ...
- js 基础篇(点击事件轮播图的实现)
轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...
- JavaScript 正则表达式语法
定义 JavaScript定义正则表达式有两种方法. 1.RegExp构造函数 var pattern = new RegExp("[bc]at","i"); ...
- Nlog配置实例
彩色Console target <?xml version="1.0" encoding="utf-8" ?> <nlog xmlns= ...
- 【python之路5】学习小结
一.编程语言 java C语言 C++ C# Python 二.python语言的种类 Cpython:python的官方版本,使用最为广泛,实现将python(py文件)转换为字节码文件(pyc文件 ...