WCF学习之旅—第三个示例之五(三十一)
WCF学习之旅目录
之前步骤请查看以下四篇文章:WCF学习之旅—第三个示例之一(二十七)
十、添加保存功能
在此步骤中,将在应用程序中添加书籍的保存功能,涉及两个功能“新增”与“修改”。
- 在解决方案资源管理器中,选中“FrmBook.cs”文件,在弹出的右键菜单中选择“打开”,或者使用鼠标左键双击。
- 在FrmBook.cs界面中,使用鼠标双击“保存”按钮与“清空”按钮
- 然后在 btnSave _Click事件处理程序中添加以下代码:
private void btnSave_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.Add(GetBookInfo()); } else textBoxMsg.Text = proxy.Edit(GetBookInfo()); } } } catch (FaultException<SQLError> fex) { SQLError error = fex.Detail; textBoxMsg.Text = string.Format("抛出一个服务端错误。\r\n\t错误代码:{0}\n\t错误原因:{1}\r\n\t操作:{2}\r\n\t错误信息:{3}\r\n\r\n", fex.Code, fex.Reason, error.Operation, error.ErrorMessage); } }
4. 在 buttonClear_Click事件处理程序中添加以下代码
private void buttonClear_Click(object sender, EventArgs e) { txtBookId.Text = string.Empty; txtAuthorID.Text = string.Empty; textBoxName.Text = string.Empty; textBoxCategory.Text = string.Empty; textBoxPrice.Text = string.Empty; textBoxRating.Text = string.Empty; textBoxNumberofcopies.Text = string.Empty; txtPublishDate.Text = string.Empty; }
5.在菜单栏上,依次选择“调试”和“启动调试”以运行应用程序。
6. 在界面中使用鼠标点击“查询”按钮,显示出全部的书籍记录。
7. 使用鼠标选中BookID=6的书籍信息,然后点击“查询选中的书籍”,这时会在“详细信息”中显示这本书的详细信息。
8. 分别修改“价格”与“出版日期”,然后使用鼠标点击“保存”按钮。
9.点击“查询”按钮,再次查询出结果,与之前的查询结果进行比较。见下图, “价格”与“出版日期”已经保存到数据库。
10.接下来,我们来看看如何新增一条书籍信息。在“书籍信息”界面中,点击“清空”按钮,然后在详细信息中分别输入“作者编号”、“书名”、“类型”、“价格”、“评价”、“出版数量”、“出版日期”,点击“保存”按钮。就新增了一条新的记录。如下图。
十一、添加删除功能
在此步骤中,将在应用程序中添加书籍的删除功能。
- 在解决方案资源管理器中,选中“FrmBook.cs”文件,在弹出的右键菜单中选择“打开”,或者使用鼠标左键双击。
- 在FrmBook.cs界面中,使用鼠标双击“删除选中书籍”按钮
- 然后在 btnDel _Click事件处理程序中添加以下代码:
private void btnDel_Click(object sender, EventArgs e) { Books book = new Books(); if (gridBooks.SelectedRows.Count > 0) { book = gridBooks.SelectedRows[0].DataBoundItem as Books; textBoxMsg.Text = XMLHelper.ToXML<Books>(book); using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService")) { IBookService proxy = channelFactory.CreateChannel(); using (proxy as IDisposable) { textBoxMsg.Text = proxy.Delete(textBoxMsg.Text); } } } else { textBoxMsg.Text = "没有选中相应的记录!"; } }
4. 在菜单栏上,依次选择“调试”和“启动调试”以运行应用程序。
5. 在界面中使用鼠标点击“查询”按钮,显示出全部的书籍记录。
6. 使用鼠标选中BookID=3的书籍信息,然后点击“删除选中书籍”。
7. 再次使用鼠标点击“查询”按钮,再次查询出结果,与之前的查询结果进行比较。见下图, “BookID=3”的记录已经被删除了。
十二、关于异常处理的小结
1. 一开始,我对异常返回的写法如下,在BookService.svc.cs文件,双击在“代码编辑器”中打开,代码如下,注意其中的“Edit”方法的异常返回,看上去没什么问题,但在具体实践中,却得到如图1的错误,看得我摸不着头脑,不知道错在什么地方。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using BookMgr.Contracts; using BookMgr.Model; using BookMgr.Common; using System.Data.Entity; namespace BookMgr.Service { // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“BookService”。 // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 BookService.svc 或 BookService.svc.cs,然后开始调试。 public class BookService :IBookService { BookEntities db = new BookEntities(); public string Add(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 Delete(string bookInfo) { try { Books book = XMLHelper.DeSerializer<Books>(bookInfo); db.Entry(book).State = EntityState.Deleted; db.SaveChanges(); } catch (Exception ex) { return ex.Message; } return "true"; } public void DoWork() { } public string Edit(string mbook) { try { Books book = XMLHelper.DeSerializer<Books>(mbook); db.Entry(book).State = EntityState.Modified; db.SaveChanges(); } catch (Exception ex) { string reason = string.Empty; if (ex.InnerException != null) { reason = string.Format("{0}。InnerException:{1}",ex.Message, ex.InnerException.Message); } else reason = ex.Message; SQLError error = new SQLError("更新数据库操作", reason); throw new FaultException<SQLError>(error, new FaultReason(reason), new FaultCode("Edit")); } return "true"; } public string Get(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); } } }
2. 异常返回值图。
图1
3. 看来之前的写法,无法获取全部的异常信息,我添加了一个获取异常的方法,把所有的内部异常信息获取出来。具体代码见下,下面只有“Edit”方法的异常处理。
StringBuilder sb = new StringBuilder(); /// <summary> /// 递归获取错误信息的内部错误信息,直到InnerException为null /// </summary> /// <param name="ex"></param> private string GetErrorMessage(Exception ex) { if (ex.InnerException != null) { sb.Append("InnerException:"+ex.Message + ","); GetErrorMessage(ex.InnerException); } else { sb.Append(ex.Message + ","); } return sb.ToString(); } public string Edit(string mbook) { try { Books book = XMLHelper.DeSerializer<Books>(mbook); db.Entry(book).State = EntityState.Modified; db.SaveChanges(); } catch (Exception ex) { string reason = GetErrorMessage(ex); SQLError error = new SQLError("更新数据库操作", reason); throw new FaultException<SQLError>(error, new FaultReason(reason), new FaultCode("Edit")); } return "true"; }
4.这样修改之后的异常返回,如下图。这样我们就能很容易知道问题出在哪里了。