WCF learning journey-Fault Contract-based Exception Handling (18th), wcfcontract
WCF learning journey-traditional exception handling in WCF (16)
WCF learning journey-ServiceDebug-based Exception Handling (17th)
Iii. Fault Contract-based Exception Handling
The second example is to obtain exceptions on the server by customizing ServiceDebug, but this method can only be used in the Debug phase. After the release of our WCF application, this exception acquisition method cannot be used in our work environment. We must find an exception handling method to obtain the corresponding exception prompt information on the client. That is the FaultContract-based solution we will introduce next. We know that WCF adopts a Contract-based approach that defines the principles and specifications for exchange between two parties. Service Contract defines the interfaces of all Operation services. Data Contract defines the structure of interactive Data, faultContract actually defines an abnormal and incorrect expression that requires interaction between the two parties. Now we will learn how to use FaultContract-based exception handling.
First, we will define a class for Fault: SQLError. Considering that this class needs to be used in Service and Client, I define it in 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; } } }}
If you see an error message, refer to System. Runtime. Serialization. dll.
SQLError defines two members: Operation indicating the error Operation and ErrorMessage indicating the error message. Because the objects of this class need to be passed between endpoints, they must be serializable. In WCF, we generally use two different serializers to implement Object and XML Serialization and Deserialization: datacontract Serializer and XML Serializer. For Fault, you can only use the former.
SQLError is defined. We need to add it to the EditBook method through the FaultContract feature. we modify the IBookService interface to the following.
Using System; using System. collections. generic; using System. linq; using System. runtime. serialization; using System. serviceModel; using System. text; namespace SCF. contracts {// Note: You can use the "RENAME" command on the "refactoring" menu to change the Interface Name "IBookService" in the Code and configuration file at the same time ". [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 );}}
FaultContract is used in the EditBook and the corresponding type of Fault is encapsulated. In the end, the FaultContract Based on the SQLError type will be written into the Service Description, by obtaining the Service Description (generally the WSDL), the client recognizes the Service Description and maps the XML Mapping of the Fault in the received Soap to the specific SQLError type.
Then, the SQLError object is implanted by throwing an Exception in the error processing on the server:
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 {// Note: You can use the "RENAME" command on the "refactoring" menu to change the class name "BookService" in the code, svc, and configuration file at the same time ". // Note: To start the WCF test client to test the service, select BookService. svc or BookService. svc. cs in Solution Explorer and start debugging. 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. A Dded; db. saveChanges ();} catch (Exception ex) {// return ex. message; SQLError error = new SQLError ("update database operation", 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 );}}}
In catch, a FaultException <SQLError> Exception is thrown, and a specific SQLError object, a FaultCode (usually the source of the error), and a FaultReason (the cause of the error) are specified ). We will not modify the code related to Exception Handling on the client, but run Hosting to see what is special in WSDL, such:
After that, we can see that some nodes are added to the wsdl definition of the EditBook method.
After finding out the expression of Fault in WSDL, we can modify the code of our client to effectively handle the exception:
Using SCF. contracts; 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 S HowBook () {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 (); dateTimePicke RPublishDate. 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_Cli Ck (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 () ;}} catc H (FaultException <SQLError> ex) {SQLError error = ex. Detail; textBoxMsg. Text = string. Format ("throws a server error. \ R \ n \ t error code: {0} \ n \ t error cause: {1} \ r \ n \ t operation: {2} \ r \ n \ t error message: {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 ;}}}
After the "save" operation is executed, the server throws the following error message: