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

Enterprise Library 深入解析與靈活應用(4):自訂 Exception Handler 實現屬性值導向異常處理

     編輯:關於.NET

前言

ELAB(Exception Handling Application Block)採用策略導向異常處理:Policy = Exception Type + Handler(s)。粒度止於異常型別,無法針對同型別異常的屬性值差異採取不同處理。例如 SqlException 可能因連線失敗或違反約束拋出,ELAB 視為同一錯誤。

解決方案:FilterableExceptionHandler

引入特殊 Handler 依異常屬性值動態決定執行哪些 Handler:

原始對應關係

引入後:

引入 FilterableExceptionHandler 後

配置範例

<filters>
  <add property="Message" value="xxx" name="filter1" typeConverter="System.ComponentModel.TypeConverter, System">
    <exceptionHandlers>
      <add exceptionMessage="Bar" replaceExceptionType="Artech.CustomExceptionHandlers.BarException, Artech.CustomExceptionHandlers.Demo" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" name="Replace Handler" />
    </exceptionHandlers>
  </add>
  <add property="Message" value="yyy" name="filter2" typeConverter="System.ComponentModel.TypeConverter, System">
    <exceptionHandlers>
      <add exceptionMessage="Baz" replaceExceptionType="Artech.CustomExceptionHandlers.BazException, Artech.CustomExceptionHandlers.Demo" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" name="Replace Handler" />
    </exceptionHandlers>
  </add>
</filters>

針對 FooException,若 Message="xxx" 替換為 BarException,若 Message="yyy" 替換為 BazException。

核心實作

1. FilterEntry 配置元素

public class FilterEntry : NamedConfigurationElement
{
    [ConfigurationProperty("property", IsRequired = true)]
    public string PropertyName { get; set; }

    [ConfigurationProperty("value", IsRequired = true)]
    public string PropertyValue { get; set; }

    [ConfigurationProperty("typeConverter", DefaultValue = "")]
    public string TypeConverterData { get; set; }

    public TypeConverter TypeConverter
    {
        get
        {
            if (string.IsNullOrEmpty(TypeConverterData)) return new TypeConverter();
            Type t = Type.GetType(TypeConverterData);
            return Activator.CreateInstance(t) as TypeConverter;
        }
    }

    [ConfigurationProperty("exceptionHandlers")]
    public NameTypeConfigurationElementCollection<ExceptionHandlerData, CustomHandlerData> ExceptionHandlers { get; }
}

2. FilterableExceptionHandlerData

[Assembler(typeof(FilterableExceptionHandlerAssembler))]
public class FilterableExceptionHandlerData : ExceptionHandlerData
{
    [ConfigurationProperty("filters", IsRequired = true)]
    public NamedElementCollection<FilterEntry> Filters { get; set; }
}

3. FilterableExceptionHandler

[ConfigurationElementType(typeof(FilterableExceptionHandlerData))]
public class FilterableExceptionHandler : IExceptionHandler
{
    private FilterableExceptionHandlerData _data;

    public FilterableExceptionHandler(FilterableExceptionHandlerData data) => _data = data;

    private IList<IExceptionHandler> GetFilteredHandler(Exception ex, FilterableExceptionHandlerData data)
    {
        var handlers = new List<IExceptionHandler>();
        foreach (FilterEntry filter in data.Filters)
        {
            PropertyInfo prop = ex.GetType().GetProperty(filter.PropertyName);
            if (prop == null) throw new ConfigurationErrorsException($"型別 {ex.GetType().Name} 無屬性 {filter.PropertyName}");

            object val = prop.GetValue(ex, null);
            string strVal = filter.TypeConverter.ConvertToString(val);
            if (string.Compare(strVal, filter.PropertyValue, true) == 0)
            {
                foreach (ExceptionHandlerData hData in filter.ExceptionHandlers)
                    handlers.Add(ExceptionHandlerCustomFactory.Instance.Create(null, hData, null, null));
            }
        }
        return handlers;
    }

    public Exception HandleException(Exception ex, Guid handlingInstanceId)
    {
        foreach (var handler in GetFilteredHandler(ex, _data))
            ex = handler.HandleException(ex, handlingInstanceId);
        return ex;
    }
}

4. Assembler

public class FilterableExceptionHandlerAssembler : IAssembler<IExceptionHandler, ExceptionHandlerData>
{
    public IExceptionHandler Assemble(IBuilderContext context, ExceptionHandlerData config, IConfigurationSource source, ConfigurationReflectionCache cache)
        => new FilterableExceptionHandler(config as FilterableExceptionHandlerData);
}

驗證測試

定義 FooException、BarException、BazException,程式拋出不同 Message 的 FooException 並經 ExceptionPolicy.HandleException 處理。輸出結果證明同型別異常依屬性值分派至不同 Handler:

Exception Type: BarException; Message: Bar
Exception Type: BazException; Message: Baz

執行結果

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

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