異常處理(Exception、FaultException、FaultException、IErrorHandler)
介紹
WCF(Windows Communication Foundation) - 異常處理:一般Exception的處理,FaultException和FaultException
示例
1、服務
IHello.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCF.ServiceLib.Exception { /**//// <summary> /// IHello接口 /// </summary> [ServiceContract] public interface IHello { /**//// <summary> /// 拋出Exception異常 /// </summary> [OperationContract] void HelloException(); /**//// <summary> /// 拋出FaultException異常 /// </summary> [OperationContract] void HelloFaultException(); /**//// <summary> /// 拋出FaultException<T>異常 /// </summary> [OperationContract] [FaultContract(typeof(FaultMessage))] void HelloFaultExceptionGeneric(); /**//// <summary> /// IErrorHandler處理異常 /// </summary> [OperationContract] void HelloIErrorHandler(); } }
FaultMessage.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Runtime.Serialization; namespace WCF.ServiceLib.Exception { /**//// <summary> /// 錯誤信息實體類(用於錯誤契約FaultContract) /// </summary> [DataContract] public class FaultMessage { /**//// <summary> /// 錯誤信息 /// </summary> [DataMember] public string Message { get; set; } /**//// <summary> /// 錯誤代碼 /// </summary> [DataMember] public int ErrorCode { get; set; } } }
FaultErrorHandler.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Dispatcher; using System.Configuration; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.ServiceLib.Exception { /**//// <summary> /// 自定義錯誤處理器(繼承自System.ServiceModel.Dispatcher.IErrorHandler) /// </summary> public class FaultErrorHandler : IErrorHandler { /**//// <summary> /// 在異常返回給客戶端之後被調用 /// </summary> /// <param name="error">異常</param> /// <returns></returns> public bool HandleError(System.Exception error) { System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\WCF_Log.txt", true); sw.Write("IErrorHandler - HandleError測試。錯誤類型:{0};錯誤信息:{1}", error.GetType().ToString(), error.Message); sw.WriteLine(); sw.Flush(); sw.Close(); // true - 已處理 return true; } /**//// <summary> /// 在異常發生後,異常信息返回前被調用 /// </summary> /// <param name="error">異常</param> /// <param name="version">SOAP版本</param> /// <param name="fault">返回給客戶端的錯誤信息</param> public void ProvideFault(System.Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault) { if (error is System.IO.IOException) { FaultException ex = new FaultException("IErrorHandler - ProvideFault測試"); MessageFault mf = ex.CreateMessageFault(); fault = Message.CreateMessage(version, mf, ex.Action); // InvalidOperationException error = new InvalidOperationException("An invalid operation has occurred."); // MessageFault mfault = MessageFault.CreateFault(new FaultCode("Server", new FaultCode(String.Format("Server.{0}", error.GetType().Name))), new FaultReason(error.Message), error); // FaultException fe = FaultException.CreateFault(mfault, typeof(InvalidOperationException)); } } } }
Hello.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; namespace WCF.ServiceLib.Exception { /**//// <summary> /// Hello類 /// </summary> public class Hello : IHello, IDisposable, IServiceBehavior { /**//// <summary> /// 拋出Exception異常 /// </summary> public void HelloException() { throw new System.Exception("拋出Exception異常"); } /**//// <summary> /// 拋出FaultException異常 /// </summary> public void HelloFaultException() { throw new FaultException("拋出FaultException異常", new FaultCode("服務")); } /**//// <summary> /// 拋出FaultException<T>異常 /// </summary> public void HelloFaultExceptionGeneric() { throw new FaultException<FaultMessage>(new FaultMessage { Message = "拋出FaultException<T>異常", ErrorCode = -1 }, "為了測試FaultException<T>用的"); } /**//// <summary> /// IErrorHandler處理異常 /// </summary> public void HelloIErrorHandler() { throw new System.IO.IOException("拋出異常,用IErrorHandler處理"); } /**//// <summary> /// 實現IDisposable接口的Dispose()方法 /// </summary> public void Dispose() { } /**//// <summary> /// 為契約增加自定義綁定參數 /// </summary> /// <param name="serviceDescription">服務描述</param> /// <param name="serviceHostBase">服務宿主</param> /// <param name="endpoints">服務端點</param> /// <param name="bindingParameters">需要增加的自定義綁定參數</param> public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } /**//// <summary> /// runtime時修改屬性值或增加自定義擴展對象 /// </summary> /// <param name="serviceDescription">服務描述</param> /// <param name="serviceHostBase">服務宿主</param> public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { IErrorHandler handler = new FaultErrorHandler(); foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) { // 增加錯誤處理器 dispatcher.ErrorHandlers.Add(handler); } } /**//// <summary> /// 檢查服務描述和服務宿主,以確認服務可以成功運行 /// </summary> /// <param name="serviceDescription">服務描述</param> /// <param name="serviceHostBase">服務宿主</param> public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } } }
2、宿主
Hello.svc
<%@ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Exception.Hello" %>
Web.config
<?xml version="1.0"?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="ExceptionBehavior"> <!--httpGetEnabled - 使用get方式提供服務--> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> <services> <!--name - 提供服務的類名--> <!--behaviorConfiguration - 指定相關的行為配置--> <service name="WCF.ServiceLib.Exception.Hello" behaviorConfiguration="ExceptionBehavior"> <!--address - 服務地址--> <!--binding - 通信方式--> <!--contract - 服務契約--> <endpoint address="" binding="wsHttpBinding" contract="WCF.ServiceLib.Exception.IHello" /> </service> </services> </system.serviceModel> </configuration>
3、客戶端
Hello.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Hello.aspx.cs" Inherits="Exception_Hello" Title="異常處理(Exception、FaultException、FaultException<T>、IErrorHandler)" %> <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server"> <div> <asp:Label ID="lblMsg" runat="server" /> </div> <br /> <div> <asp:Button ID="btnHelloException" runat="server" Text="HelloException" OnClick="btnHelloException_Click" /> </div> <div> <asp:Button ID="btnHelloFaultException" runat="server" Text="HelloFaultException" OnClick="btnHelloFaultException_Click" /> </div> <div> <asp:Button ID="btnHelloFaultExceptionGeneric" runat="server" Text="HelloFaultExceptionGeneric" OnClick="btnHelloFaultExceptionGeneric_Click" /> </div> <div> <asp:Button ID="btnHelloIErrorHandler" runat="server" Text="HelloIErrorHandler" OnClick="btnHelloIErrorHandler_Click" /> </div> </asp:Content>
Hello.aspx.cs
using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.ServiceModel; public partial class Exception_Hello : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnHelloException_Click(object sender, EventArgs e) { ExceptionService.HelloClient proxy = new ExceptionService.HelloClient(); try { proxy.HelloException(); } catch (Exception ex) { lblMsg.Text = ex.Message; } finally { try { proxy.Close(); } catch (Exception ex) { lblMsg.Text += "<br />" + ex.Message; } } } protected void btnHelloFaultException_Click(object sender, EventArgs e) { ExceptionService.HelloClient proxy = new ExceptionService.HelloClient(); try { proxy.HelloFaultException(); } catch (FaultException ex) { lblMsg.Text = string.Format("錯誤編碼:{0};錯誤原因:{1}", ex.Code.Name, ex.Reason.ToString()); } finally { proxy.Close(); } } protected void btnHelloFaultExceptionGeneric_Click(object sender, EventArgs e) { ExceptionService.HelloClient proxy = new ExceptionService.HelloClient(); try { proxy.HelloFaultExceptionGeneric(); } catch (System.ServiceModel.FaultException<ExceptionService.FaultMessage> ex) { lblMsg.Text = string.Format("錯誤代碼:{0};錯誤信息:{1};錯誤原因:{2}", ex.Detail.ErrorCode.ToString(), ex.Detail.Message, ex.Reason.ToString()); } finally { proxy.Close(); } } protected void btnHelloIErrorHandler_Click(object sender, EventArgs e) { ExceptionService.HelloClient proxy = new ExceptionService.HelloClient(); try { proxy.HelloIErrorHandler(); } catch (Exception ex) { System.ServiceModel.FaultException faultException = ex as System.ServiceModel.FaultException; if (faultException != null) { lblMsg.Text = string.Format("錯誤信息:{0}", faultException.Message); } else { lblMsg.Text = ex.ToString(); } } finally { proxy.Close(); } } }
Web.config
<?xml version="1.0"?> <configuration> <system.serviceModel> <client> <!--address - 服務地址--> <!--binding - 通信方式--> <!--contract - 服務契約--> <endpoint address="http://localhost:3502/ServiceHost/Exception/Hello.svc" binding="wsHttpBinding" contract="ExceptionService.IHello" /> </client> </system.serviceModel> </configuration>
運行結果:
單擊"btnHelloException"後顯示
拋出Exception異常
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.
單擊"btnHelloFaultException"後顯示
錯誤編碼:服務;錯誤原因:拋出FaultException異常
單擊"btnHelloFaultExceptionGeneric"後顯示
錯誤代碼:-1;錯誤信息:拋出FaultException異常;錯誤原因:為了測試FaultException用的
單擊"btnHelloIErrorHandler"後顯示
錯誤信息:IErrorHandler - ProvideFault測試
OK