異常處理(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