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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.Text;
  7.  
  8. namespace SCF.Contracts
  9.  
  10. {
  11.  
  12. // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IBookService”。
  13.  
  14. [ServiceContract]
  15. public interface IBookService
  16. {
  17.  
  18. [OperationContract]
  19. void DoWork();
  20.  
  21. [OperationContract]
  22. string GetBook(string Id);
  23.  
  24. [OperationContract]
  25. string AddBook(string book);
  26.  
  27. [OperationContract]
  28. string EditBook(string book);
  29.  
  30. [OperationContract]
  31. string Search(string Category, string searchString);
  32.  
  33. }
  34.  
  35. }

2.  SCF.WcfService

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.Text;
  7. using System.Data.Entity;
  8. using SCF.Contracts;
  9. using SCF.Model;
  10. using SCF.Common;
  11.  
  12. namespace SCF.WcfService
  13.  
  14. {
  15.  
  16. // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“BookService”。
  17.  
  18. // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 BookService.svc 或 BookService.svc.cs,然后开始调试。
  19.  
  20. public class BookService : IBookService
  21.  
  22. {
  23.  
  24. Entities db = new Entities();
  25. public string AddBook(string mbook)
  26. {
  27.  
  28. try
  29. {
  30. Books book = XMLHelper.DeSerializer<Books>(mbook);
  31. db.Books.Add(book);
  32. db.SaveChanges();
  33. }
  34. catch (Exception ex)
  35. {
  36. return ex.Message;
  37. }
  38.  
  39. return "true";
  40.  
  41. }
  42.  
  43. public void DoWork()
  44. {
  45.  
  46. }
  47.  
  48. public string EditBook(string mbook)
  49. {
  50.  
  51. try
  52. {
  53.  
  54. Books book = XMLHelper.DeSerializer<Books>(mbook);
  55. db.Entry(book).State = EntityState.Added;
  56. db.SaveChanges();
  57. }
  58. catch (Exception ex)
  59. {
  60. //return ex.Message;
  61. throw ex;
  62. }
  63. return "true";
  64.  
  65. }
  66.  
  67. public string GetBook(string Id)
  68. {
  69.  
  70. int bookId = Convert.ToInt32(Id);
  71. Books book= db.Books.Find(bookId);
  72. string xml=XMLHelper.ToXML<Books>(book);
  73. return xml;
  74. //throw new NotImplementedException();
  75.  
  76. }
  77.  
  78. public string Search(string Category, string searchString)
  79. {
  80.  
  81. var cateLst = new List<string>();
  82.  
  83. var cateQry = from d in db.Books
  84. orderby d.Category
  85. select d.Category;
  86. cateLst.AddRange(cateQry.Distinct());
  87.  
  88. var books = from m in db.Books
  89. select m;
  90.  
  91. if (!String.IsNullOrEmpty(searchString))
  92. {
  93. books = books.Where(s => s.Name.Contains(searchString));
  94. }
  95.  
  96. List<Books> list = null;
  97. if (string.IsNullOrEmpty(Category))
  98. {
  99. list = books.ToList<Books>();
  100. //return XMLHelper.ToXML<List<Books>>(list);
  101. }
  102. else
  103. {
  104. list = books.Where(x => x.Category == Category).ToList<Books>();
  105. // return XMLHelper.ToXML<IQueryable<Books>>(books.Where(x => x.Category == Category));
  106. }
  107. return XMLHelper.ToXML<List<Books>>(list);
  108. }
  109.  
  110. }
  111.  
  112. }

注:在编辑书籍信息时,会抛出一个DbUpdateException信息。我在数据库中设了一个唯一索引,不能插入重复值

3.  Service Hosting

配置文件信息如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <configuration>
  3. <configSections>
  4. <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  5. <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  6.  
  7. </configSections>
  8. <entityFramework>
  9. <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  10. <providers>
  11. <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  12. </providers>
  13. </entityFramework>
  14.  
  15. <system.serviceModel>
  16.  
  17. <behaviors>
  18. <serviceBehaviors>
  19. <behavior name="metadataBehavior">
  20. <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8888/BookService/metadata" />
  21. <serviceDebug includeExceptionDetailInFaults="True" />
  22. </behavior>
  23. </serviceBehaviors>
  24.  
  25. </behaviors>
  26.  
  27. <services>
  28. <service behaviorConfiguration="metadataBehavior" name="SCF.WcfService.BookService">
  29. <endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
  30. contract="SCF.Contracts.IBookService" />
  31. </service>
  32. </services>
  33. </system.serviceModel>
  34.  
  35. <startup>
  36.  
  37. <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  38. </startup>
  39.  
  40. <connectionStrings>
  41. <add name="TestEntities" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Test;Integrated Security=SSPI"
    providerName="System.Data.SqlClient" />
  42. <add name="Entities" connectionString="metadata=res://*/BookModel.csdl|res://*/BookModel.ssdl|
    res://*/BookModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQLEXPRESS;initial catalog
    =Test;integrated security=SSPI;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  43. </connectionStrings>
  44. </configuration>

Host程序代码如下:

  1. using SCF.WcfService;
  2. using SCF.Contracts;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.ServiceModel;
  7. using System.ServiceModel.Description;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10.  
  11. namespace Hosting
  12. {
  13. class Program
  14. {
  15.  
  16. static void Main(string[] args)
  17. {
  18. try
  19. {
  20. using (ServiceHost host = new ServiceHost(typeof(BookService)))
  21. {
  22. host.Opened += delegate
  23. {
  24. Console.WriteLine("BookService,使用配置文件,按任意键终止服务!");
  25. };
  26. host.Open();
  27. Console.ForegroundColor = ConsoleColor.Yellow;
  28. foreach (ServiceEndpoint se in host.Description.Endpoints)
  29. {
  30. Console.WriteLine("[终结点]: {0}\r\n\t[A-地址]: {1} \r\n\t [B-绑定]: {2} \r\n\t [C-协定]: {3}",
  31. se.Name, se.Address, se.Binding.Name, se.Contract.Name);
  32.  
  33. }
  34.  
  35. Console.Read();
  36. }
  37. }
  38. catch (Exception ex)
  39. {
  40.  
  41. Console.WriteLine(ex.Message);
  42. }
  43.  
  44. //Console.Read();
  45. }
  46. }
  47. }

4.  客户端代码如下

配置文件信息如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <startup>
  4. <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  5. </startup>
  6.  
  7. <system.serviceModel>
  8. <bindings>
  9. <wsHttpBinding>
  10. <binding name="WSHttpBinding_IBookService" />
  11. <binding name="WSHttpBinding_IBookService1" />
  12.  
  13. </wsHttpBinding>
  14. <customBinding>
  15. <binding name="listenUriBinding">
  16. <textMessageEncoding />
  17. <httpTransport />
  18. </binding>
  19. </customBinding>
  20. </bindings>
  21. <client>
  22. <endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
    bindingConfiguration="WSHttpBinding_IBookService" contract="SCF.Contracts.IBookService"
  23. name="WSHttpBinding_IBookService">
  24. <identity>
  25. <userPrincipalName value="DEVELOPER\Administrator" />
  26.  
  27. </identity>
  28. </endpoint>
  29. <endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
  30. bindingConfiguration="WSHttpBinding_IBookService1" contract="BookServiceRef.IBookService"
  31. name="WSHttpBinding_IBookService1">
  32. <identity>
  33. <userPrincipalName value="DEVELOPER\Administrator" />
  34. </identity>
  35. </endpoint>
  36. </client>
  37. </system.serviceModel>
  38. </configuration>

客户端程序代码如下:

  1. using SCF.Contracts;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.ServiceModel;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. using SCF.Model;
  13. using SCF.Common;
  14.  
  15. namespace WinClient
  16. {
  17.  
  18. public partial class FrmBook : Form
  19. {
  20. public FrmBook()
  21.  
  22. {
  23. InitializeComponent();
  24. }
  25.  
  26. private void btnGetBook_Click(object sender, EventArgs e)
  27. {
  28. Books book = new Books();
  29. BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
  30. if (gridBooks.SelectedRows.Count > )
  31. {
  32. book = gridBooks.SelectedRows[].DataBoundItem as Books;
  33.  
  34. textBoxMsg.Text = bookSvrClient.GetBook(book.BookID.ToString());
  35. ShowBook();
  36. }
  37. else
  38. {
  39. textBoxMsg.Text = "没有选中相应的记录!";
  40. }
  41. }
  42.  
  43. /// <summary>
  44. /// ChannelFactory方式,直接在代码中写配置信息
  45. /// </summary>
  46. /// <param name="sender"></param>
  47. /// <param name="e"></param>
  48. private void buttonChannelFactory_Click(object sender, EventArgs e)
  49. {
  50.  
  51. using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>
  52. (new WSHttpBinding(), "http://127.0.0.1:8888/BookService"))
  53. {
  54. IBookService proxy = channelFactory.CreateChannel();
  55. using (proxy as IDisposable)
  56. {
  57. textBoxMsg.Text = proxy.GetBook("");
  58. ShowBook();
  59. }
  60. }
  61.  
  62. }
  63.  
  64. /// <summary>
  65. /// ChannelFactory配置方式,在配置文件中写配置信息
  66. /// </summary>
  67. /// <param name="sender"></param>
  68. /// <param name="e"></param>
  69. private void buttonChannelConfig_Click(object sender, EventArgs e)
  70. {
  71. using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService"))
  72. {
  73. IBookService proxy = channelFactory.CreateChannel();
  74. using (proxy as IDisposable)
  75. {
  76. textBoxMsg.Text = proxy.GetBook("");
  77. ShowBook();
  78. }
  79. }
  80. }
  81.  
  82. private void ShowBook()
  83. {
  84. Books book = XMLHelper.DeSerializer<Books>(textBoxMsg.Text);
  85. txtBookId.Text = book.BookID.ToString();
  86. txtAuthorID.Text = book.AuthorID.ToString();
  87. textBoxName.Text = book.Name;
  88.  
  89. textBoxCategory.Text = book.Category.ToString();
  90. textBoxPrice.Text = book.Price.ToString();
  91. textBoxRating.Text = book.Rating.ToString();
  92. textBoxNumberofcopies.Text = book.Numberofcopies.ToString();
  93. dateTimePickerPublishDate.Text = book.PublishDate.ToString();
  94. }
  95.  
  96. private void btnSearch_Click(object sender, EventArgs e)
  97. {
  98.  
  99. BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
  100. textBoxMsg.Text = bookSvrClient.Search(string.Empty, string.Empty);
  101. List < Books > books= XMLHelper.DeSerializer<List<Books>>(textBoxMsg.Text);
  102. gridBooks.DataSource = books;
  103. }
  104.  
  105. private void btnSearchCategory_Click(object sender, EventArgs e)
  106. {
  107. BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
  108. textBoxMsg.Text = bookSvrClient.Search(txtCategory.Text, string.Empty);
  109. List<Books> books = XMLHelper.DeSerializer<List<Books>>(textBoxMsg.Text);
  110. gridBooks.DataSource = books;
  111. }
  112.  
  113. private void buttonSave_Click(object sender, EventArgs e)
  114. {
  115. try
  116. {
  117. using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService"))
  118. {
  119. IBookService proxy = channelFactory.CreateChannel();
  120. using (proxy as IDisposable)
  121. {
  122. if (string.IsNullOrEmpty(txtBookId.Text))
  123. {
  124. textBoxMsg.Text = proxy.AddBook(GetBookInfo());
  125.  
  126. }
  127. else
  128. textBoxMsg.Text = proxy.EditBook(GetBookInfo());
  129.  
  130. }
  131. }
  132. }
  133. catch (Exception ex)
  134.  
  135. {
  136. throw ex;
  137. }
  138.  
  139. }
  140.  
  141. public String GetBookInfo()
  142. {
  143. Books book = new Books();
  144. book.AuthorID = NumberHelper.ToInt(txtAuthorID.Text);
  145. book.BookID = NumberHelper.ToInt(txtBookId.Text);
  146. book.Category = textBoxCategory.Text;
  147. book.Name = textBoxName.Text;
  148. book.Numberofcopies = NumberHelper.ToInt(textBoxNumberofcopies.Text);
  149. book.Price = NumberHelper.ToDecimal(textBoxPrice.Text);
  150. book.PublishDate = dateTimePickerPublishDate.Value;
  151. book.Rating = textBoxRating.Text;
  152. textBoxMsg.Text = XMLHelper.ToXML<Books>(book);
  153. return textBoxMsg.Text;
  154. }
  155.  
  156. }
  157.  
  158. }

把Service调用放在一个try/catch 程序代码段中,看看Service端抛出的DbUpdateException能否被Catch。

现在我们运行这个程序,看看客户端报错信息如下:

我们发现客户端无法捕捉服务端真正抛出的出错信息,而是一个比较通用的FaultException。错误信息也是很通用的一种,无法有效提供详细的错误信息,以供我们来解决问题。

WCF学习之旅—WCF中传统的异常处理(十六)的更多相关文章

  1. WCF学习之旅—基于Fault Contract 的异常处理(十八)

       WCF学习之旅—WCF中传统的异常处理(十六) WCF学习之旅—基于ServiceDebug的异常处理(十七) 三.基于Fault Contract 的异常处理 第二个示例是通过定制Servic ...

  2. WCF学习之旅—WCF服务部署到IIS7.5(九)

    上接   WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...

  3. WCF学习之旅—WCF服务部署到应用程序(十)

    上接  WCF学习之旅—WCF寄宿前的准备(八) WCF学习之旅—WCF服务部署到IIS7.5(九) 五.控制台应用程序宿主 (1) 在解决方案下新建控制台输出项目 ConsoleHosting.如下 ...

  4. WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)

    上接    WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...

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

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

  6. WCF学习之旅—WCF服务的批量寄宿(十三)

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

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

    二.WCF服务端应用程序 第一步,创建WCF服务应用程序项目 打开Visual Studio 2015,在菜单上点击文件—>新建—>项目—>WCF服务应用程序.在弹出界面的“名称”对 ...

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

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

  9. WCF学习之旅—WCF第二个示例(六)

    第五步,创建数据服务 在“解决方案资源管理器”中,使用鼠标左键选中“SCF.WcfService”项目,然后在菜单栏上,依次选择“项目”.“添加新项”. 在“添加新项”对话框中,选择“Web”节点,然 ...

  10. WCF学习之旅—HTTP双工模式(二十)

    WCF学习之旅—请求与答复模式和单向模式(十九) 四.HTTP双工模式 双工模式建立在上文所实现的两种模式的基础之上,实现客户端与服务端相互调用:前面介绍的两种方法只是在客户端调用服务端的方法,然后服 ...

随机推荐

  1. 轻量级“集合”迭代器-Generator

    Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Generator的改进之前,我们先通过一个简单却显而易见的例子来了解下G ...

  2. CSS Position 定位属性

    本篇文章主要介绍元素的Position属性,此属性可以设置元素在页面的定位方式. 目录 1. 介绍 position:介绍position的值以及辅助属性. 2. position 定位方式:介绍po ...

  3. 使用etree.HTML的编码问题

    title: 使用etree.HTML的编码问题 date: 2015-10-07 17:56:47 categories: [Python] tags: [Python, lxml, Xpath] ...

  4. Xamarin+Prism开发详解二:Xaml文件如何简单绑定Resources资源文件内容

    我们知道在UWP里面有Resources文件xxx.resx,在Android里面有String.Xml文件等.那跨平台如何统一这些类别不一的资源文件以及Xaml设计文件如何绑定这些资源?应用支持多国 ...

  5. 【知识必备】RxJava+Retrofit二次封装最佳结合体验,打造懒人封装框架~

    一.写在前面 相信各位看官对retrofit和rxjava已经耳熟能详了,最近一直在学习retrofit+rxjava的各种封装姿势,也结合自己的理解,一步一步的做起来. 骚年,如果你还没有掌握ret ...

  6. CentOS下mysql数据库常用命令总结

    mysql数据库使用总结 本文主要记录一些mysql日常使用的命令,供以后查询. 1.更改root密码 mysqladmin -uroot password 'yourpassword' 2.远程登陆 ...

  7. PHP代码优化

    1 代码优化 1 尽量静态化 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍. 当然了,这个测试方法需要在十万级以上次执行,效果才明显. 其实静态方法和 ...

  8. ASP.NET Core 中文文档 第五章 测试(5.2)集成测试

    原文: Integration Testing 作者: Steve Smith 翻译: 王健 校对: 孟帅洋(书缘) 集成测试确保应用程序的组件组装在一起时正常工作. ASP.NET Core支持使用 ...

  9. 浅谈Slick(2)- Slick101:第一个动手尝试的项目

    看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...

  10. prometheus监控系统

    关于Prometheus Prometheus是一套开源的监控系统,它将所有信息都存储为时间序列数据:因此实现一种Profiling监控方式,实时分析系统运行的状态.执行时间.调用次数等,以找到系统的 ...