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

ASP.NET MVC 整合 EntLib 實現自動化異常處理:實作篇

     編輯:關於ASP.NET

架構概覽

透過自訂 ExtendedController 基類,覆寫 OnException 整合 Enterprise Library Exception Handling Application Block (EHAB),實現聲明式異常處理策略。

核心屬性:ExceptionPolicyAttribute & HandleErrorActionAttribute

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ExceptionPolicyAttribute : Attribute
{
    public string ExceptionPolicyName { get; }
    public ExceptionPolicyAttribute(string policyName) { ExceptionPolicyName = policyName; }
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class HandleErrorActionAttribute : Attribute
{
    public string HandleErrorAction { get; }
    public HandleErrorActionAttribute(string actionName) { HandleErrorAction = actionName; }
}

ExtendedController 實作細節

public class ExtendedController : Controller
{
    private static Dictionary<Type, ControllerDescriptor> _controllerDescriptors = new Dictionary<Type, ControllerDescriptor>();
    private static object _sync = new object();
    
    // 快取 ControllerDescriptor
    public ControllerDescriptor Descriptor
    {
        get
        {
            Type type = GetType();
            if (_controllerDescriptors.TryGetValue(type, out var desc)) return desc;
            lock (_sync)
            {
                if (_controllerDescriptors.TryGetValue(type, out desc)) return desc;
                desc = new ReflectedControllerDescriptor(type);
                _controllerDescriptors[type] = desc;
                return desc;
            }
        }
    }
    
    // 取得異常處理策略名稱 (Action > Controller > 預設空字串)
    public string GetExceptionPolicyName()
    {
        string actionName = ControllerContext.RouteData.GetRequiredString("action");
        var actionDesc = Descriptor.FindAction(ControllerContext, actionName);
        if (actionDesc == null) return String.Empty;
        
        return actionDesc.GetCustomAttributes(true).OfType<ExceptionPolicyAttribute>().FirstOrDefault()?.ExceptionPolicyName
            ?? Descriptor.GetCustomAttributes(true).OfType<ExceptionPolicyAttribute>().FirstOrDefault()?.ExceptionPolicyName
            ?? String.Empty;
    }
    
    // 取得錯誤處理 Action 名稱
    public string GetHandleErrorActionName()
    {
        string actionName = ControllerContext.RouteData.GetRequiredString("action");
        var actionDesc = Descriptor.FindAction(ControllerContext, actionName);
        if (actionDesc == null) return String.Empty;
        
        return actionDesc.GetCustomAttributes(true).OfType<HandleErrorActionAttribute>().FirstOrDefault()?.HandleErrorAction
            ?? Descriptor.GetCustomAttributes(true).OfType<HandleErrorActionAttribute>().FirstOrDefault()?.HandleErrorAction
            ?? String.Empty;
    }
    
    // 專用 ActionInvoker 執行錯誤 Action
    public HandleErrorActionInvoker HandleErrorActionInvoker { get; private set; }
    public ExtendedController() { HandleErrorActionInvoker = new HandleErrorActionInvoker(); }
    
    // 核心異常處理邏輯
    protected override void OnException(ExceptionContext filterContext)
    {
        // 1. 取得策略名稱
        string policyName = GetExceptionPolicyName();
        if (String.IsNullOrEmpty(policyName)) return; // 無策略則不處理
        
        // 2. 執行 EHAB 處理
        var ex = filterContext.Exception;
        var handled = ExceptionPolicy.HandleException(ex, policyName); // EntLib 核心呼叫
        
        // 3. 根據請求類型回應
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            // AJAX: 回傳 JSON 異常資訊
            var errorData = new { Message = ex.Message, StackTrace = ex.StackTrace };
            filterContext.Result = new JsonResult { Data = errorData, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
        }
        else
        {
            // 一般請求: 嘗試執行 HandleErrorAction
            string errorAction = GetHandleErrorActionName();
            if (!String.IsNullOrEmpty(errorAction))
            {
                var errorActionDesc = Descriptor.FindAction(ControllerContext, errorAction);
                if (errorActionDesc != null)
                {
                    filterContext.Result = HandleErrorActionInvoker.InvokeAction(ControllerContext, errorActionDesc);
                    filterContext.ExceptionHandled = true;
                    return;
                }
            }
            // 找不到則顯示預設錯誤 View
            filterContext.Result = View("Error");
        }
        filterContext.ExceptionHandled = true;
    }
}

HandleErrorActionInvoker

public class HandleErrorActionInvoker : ControllerActionInvoker
{
    protected override ActionResult InvokeAction(ControllerContext controllerContext, string actionName)
    {
        var controllerDesc = new ReflectedControllerDescriptor(controllerContext.Controller.GetType());
        var actionDesc = controllerDesc.FindAction(controllerContext, actionName);
        return InvokeAction(controllerContext, actionDesc);
    }
}

EntLib 配置範例 (web.config)

<configSections>
  <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" />
</configSections>
<exceptionHandling>
  <exceptionPolicies>
    <add name="defaultPolicy">
      <exceptionTypes>
        <add name="All Exceptions" type="System.Exception" postHandlingAction="NotifyRethrow">
          <exceptionHandlers>
            <add name="Logging Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging" 
                 logCategory="Exception" eventId="100" severity="Error" title="Enterprise Library Exception Handling" 
                 formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" 
                 priority="0" />
            <add name="Wrap Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WrapHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" 
                 wrapExceptionType="System.ApplicationException, mscorlib" wrapExceptionMessage="系統錯誤" />
          </exceptionHandlers>
        </add>
      </exceptionTypes>
    </add>
  </exceptionPolicies>
</exceptionHandling>

使用範例

[ExceptionPolicy("defaultPolicy")]
public class HomeController : ExtendedController
{
    [HttpPost]
    [HandleErrorAction("OnIndexError")]
    public ActionResult Index(LoginInfo loginInfo)
    {
        if (loginInfo.UserName != "foo") throw new InvalidUserNameException();
        if (loginInfo.Password != "password") throw new InvalidPasswordException();
        return View(loginInfo);
    }
    
    public ActionResult OnIndexError(LoginInfo loginInfo) => View(loginInfo);
}

總結

透過 ExtendedController.OnException 整合 EntLib EHAB,配合 ExceptionPolicyAttribute (策略) 與 HandleErrorActionAttribute (錯誤頁面 Action),實現聲明式、可配置、情境化的自動化異常處理。AJAX 自動回傳 JSON,一般請求優先執行指定錯誤 Action,最後回退預設錯誤 View。

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