首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Enterprise Library 深入解析與靈活應用(8):WCF 與 Exception Handling Application Block 整合(下)

     編輯:關於.NET

前言

在上一篇文章中,我們詳細介紹了如何透過自訂 ClientMessageInspector 與 ErrorHandler,實現 WCF 與微軟企業庫中 Exception Handling Application Block(EHAB)的整合。核心思路是:當服務端拋出異常時,利用 EHAB 依據預設的異常處理策略進行處理;接著將處理後的異常封裝進 ServiceExceptionDetail 物件,序列化後置入 Fault 訊息回傳給客戶端;客戶端收到 Fault 訊息後,提取並重建異常,最後拋出以便依據客戶端設定的策略進一步處理。

動態新增錯誤描述的必要性

為了讓 WCF 能正確序列化與反序列化 ServiceExceptionDetail,必須透過 FaultContractAttribute 將其定義為錯誤契約,如下所示:

[ServiceContract(Namespace = "https://www.artech.com/")]
public interface ICalculator
{
    [OperationContract]
    [ExceptionHandlingBehavior("myExceptionPolicy")]
    [FaultContract(typeof(ServiceExceptionDetail), Action = "https://www.artech.com/fault")]
    int Divide(int x, int y);
}

若服務提供給第三方使用,這類錯誤契約定義是必要的,因為型別資訊需透過中繼資料發布。但若服務僅供內部應用呼叫,我們可以在執行期動態加入錯誤描述,免去在每個作業方法上重複標註 Attribute。

一、透過自訂 ServiceHost 動態新增錯誤描述(服務端)

我們可以繼承 ServiceHost,在 OnOpening 方法中為所有作業加入基於 ServiceExceptionDetail 的錯誤描述:

public class ExceptionHandlingServiceHost : ServiceHost
{
    public ExceptionHandlingServiceHost(Type t, params Uri[] baseAddresses)
        : base(t, baseAddresses) { }

    protected override void OnOpening()
    {
        base.OnOpening();
        foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
        {
            foreach (OperationDescription operation in endpoint.Contract.Operations)
            {
                FaultDescription faultDescription = new FaultDescription(ServiceExceptionDetail.FaultAction);
                faultDescription.DetailType = typeof(ServiceExceptionDetail);
                operation.Faults.Add(faultDescription);
            }
        }
    }
}

邏輯簡單:遍歷所有端點與作業,加入指定 Action 的 FaultDescription。此自訂 ServiceHost 適用於非 IIS/WAS 託管情境;若需在 IIS/WAS 中使用,則需搭配 ServiceHostFactory:

public class ExceptionHandlingServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new ExceptionHandlingServiceHost(serviceType, baseAddresses);
    }
}

二、透過自訂 ChannelFactory<TChannel> 動態新增錯誤描述(客戶端)

客戶端同樣需要錯誤描述以利反序列化,我們透過覆寫 CreateDescription 方法實現:

public class ExceptionHandlingChannelFactory<TChannel> : ChannelFactory<TChannel>
{
    public ExceptionHandlingChannelFactory(string endpointConfigurationName)
        : base(endpointConfigurationName) { }

    protected override ServiceEndpoint CreateDescription()
    {
        ServiceEndpoint serviceEndpoint = base.CreateDescription();
        foreach (OperationDescription operation in serviceEndpoint.Contract.Operations)
        {
            FaultDescription faultDescription = new FaultDescription(ServiceExceptionDetail.FaultAction);
            faultDescription.DetailType = typeof(ServiceExceptionDetail);
            operation.Faults.Add(faultDescription);
        }
        return serviceEndpoint;
    }
}

三、實例示範

移除介面上的 FaultContractAttribute:

[ServiceContract(Namespace = "https://www.artech.com/")]
public interface ICalculator
{
    [OperationContract]
    [ExceptionHandlingBehavior("myExceptionPolicy")]
    int Divide(int x, int y);
}

服務託管時直接使用自訂 Host:

using (ExceptionHandlingServiceHost host = new ExceptionHandlingServiceHost(typeof(CalculatorService)))
{
    host.Open();
    Console.Read();
}

客戶端使用自訂 ChannelFactory 建立 Proxy:

using (ExceptionHandlingChannelFactory<ICalculator> channelFactory = new ExceptionHandlingChannelFactory<ICalculator>("calculatorservice"))
{
    ICalculator calculator = channelFactory.CreateChannel();
    using (calculator as IDisposable)
    {
        try
        {
            int result = calculator.Divide(1, 0);
        }
        catch (CalculationException ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine("InnerException");
            Console.WriteLine("\tType:{0}", ex.InnerException.GetType());
            Console.WriteLine("\tMessage:{0}", ex.InnerException.Message);
        }
    }
}

執行結果與上篇一致:

計算錯誤
InnerException
Type:System.DivideByZeroException
Message:嘗試除以零.

本文完整原始碼可供下載參考。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved