ASP.NET MVC集積EntLib実現「自動化」異常処理[実現編]

26604 ワード

実例編」の実演により、実装された自動異常処理メカニズムを拡張することによって、実行された処理ポリシーに従って、あるアクションメソッドの実行中に投げ出された異常を、EntLibのEHABを利用して処理できることが明らかになった.処理後の結果については、以下のように要求に応答する.[ソースコードはここからダウンロード][本明細書は『How ASP.NET MVC Works?』に同期されている]
  • Ajax要求に対して、処理後の異常をカプセル化するためのデータオブジェクトを直接作成し、これに基づいてJsonResultを作成して異常情報をクライアントに返信する.
  • 非Ajaxリクエストに対して、現在のActionメソッドにHandleErrorActionAttributeプロパティが適用されている場合、一致するActionメソッドが、そのメソッドによって投げ出された例外を処理するために設定されている場合、このメソッドが実行され、返されたActionResultオブジェクトが現在のリクエストに応答する.
  • HandleErrorActionAttributeプロパティが現在のActionメソッドに適用されていない場合、またはそのプロパティによって指定されたActionが存在しない場合、デフォルトのエラーViewはマルチリクエストの応答として表示されます.

  • ディレクトリ1、ExceptionPolicyAttribute&HandleErrorActionAttribute 2、OnExceptionメソッドでの例外処理ロジックを実現する3、処理後のエラーメッセージをHttpContextのItemsに格納する4、エラーメッセージを設定するためのErrorMessageHandler

    一、ExceptionPolicyAttribute&HandleErrorActionAttribute


    これらはすべて、カスタムExceptionFilterによって実現されます.ただし、ExceptionFilterプロパティを定義するのではなく、カスタムのExtendedControllerベースクラスに例外処理を実装し、例外の自動処理を書き換えたOnExceptionメソッドに実装しますが、このメソッドの論理を説明する前に、ExtendedControllerで定義されている他の補助メンバーを見てみましょう.
       1: public class ExtendedController: Controller
       2: {
       3:     private static Dictionary<Type, ControllerDescriptor> controllerDescriptors = new Dictionary<Type, ControllerDescriptor>();
       4:     private static object syncHelper = new object();
       5:  
       6:     protected override void OnException(ExceptionContext filterContext)
       7:     {
       8:         //    
       9:     }      
      10:     
      11:     //    Controller ControllerDescriptor
      12:     public ControllerDescriptor Descriptor
      13:     {
      14:         get
      15:         {
      16:             ControllerDescriptor descriptor;
      17:             if(controllerDescriptors.TryGetValue(this.GetType(), out descriptor))
      18:             {
      19:                 return descriptor;
      20:             }
      21:             lock (syncHelper)
      22:             {
      23:                 if (controllerDescriptors.TryGetValue(this.GetType(), out descriptor))
      24:                 {
      25:                     return descriptor;
      26:                 }
      27:                 else
      28:                 {
      29:                     descriptor = new ReflectedControllerDescriptor(this.GetType());
      30:                     controllerDescriptors.Add(this.GetType(), descriptor);
      31:                     return descriptor;
      32:                 }
      33:             }
      34:         }
      35:     }
      36:     //          
      37:     public string GetExceptionPolicyName()
      38:     {
      39:         string actionName = ControllerContext.RouteData.GetRequiredString("action");
      40:         ActionDescriptor actionDescriptor = this.Descriptor.FindAction(ControllerContext, actionName);
      41:         if (null == actionDescriptor)
      42:         {
      43:             return string.Empty;
      44:         }
      45:         ExceptionPolicyAttribute exceptionPolicyAttribute = actionDescriptor.GetCustomAttributes(true).OfType<ExceptionPolicyAttribute>().FirstOrDefault()??               
      46:            Descriptor.GetCustomAttributes(true).OfType<ExceptionPolicyAttribute>().FirstOrDefault()?? new ExceptionPolicyAttribute("");
      47:         return exceptionPolicyAttribute.ExceptionPolicyName;
      48:     }
      49:  
      50:     //  Handle-Error-Action  
      51:     public string GetHandleErrorActionName()
      52:     {
      53:         string actionName = ControllerContext.RouteData.GetRequiredString("action");
      54:         ActionDescriptor actionDescriptor = this.Descriptor.FindAction(ControllerContext, actionName);
      55:         if (null == actionDescriptor)
      56:         {
      57:             return string.Empty;
      58:         }
      59:         HandleErrorActionAttribute handleErrorActionAttribute = actionDescriptor.GetCustomAttributes(true).OfType<HandleErrorActionAttribute>().FirstOrDefault()??          
      60:             Descriptor.GetCustomAttributes(true).OfType<HandleErrorActionAttribute>().FirstOrDefault()?? new HandleErrorActionAttribute("");
      61:         return handleErrorActionAttribute.HandleErrorAction;
      62:     }
      63:  
      64:     //    Handle-Error-Action ActionInvoker
      65:     public HandleErrorActionInvoker HandleErrorActionInvoker { get; private set; }
      66:  
      67:     public ExtendedController()
      68:     {
      69:         this.HandleErrorActionInvoker = new HandleErrorActionInvoker();
      70:     }
      71: }

    ExtendedControllerのDescriptorプロパティは、自身を記述するControllerDescriptorオブジェクトを返すために使用されます.実際にはReflectedControllerDescriptorオブジェクトです.頻繁な反射動作によるパフォーマンスへの影響を回避するために、あるタイプの解析に基づいたReflectedControllerDescriptorオブジェクトをグローバルにキャッシュします.
    GetExceptionPolicyNameメソッドは、現在使用されている例外処理ポリシーの名前を返すために使用されます.例外処理ポリシー名は、次のように定義されたExceptionPolicyAttributeプロパティによって指定されます.この特性はControllerタイプにも適用でき,Actionメソッドにも適用でき,言い換えれば,異なるAction実行中に投げ出された異常を処理するために異なるポリシーを用いることができる.GetExceptionPolicyNameは、ControllerDesciorおよびActionDescriptorを使用して、アプリケーションのExceptionPolicyAttributeプロパティを簡単に入手し、対応する例外処理ポリシー名を得ることができます.
       1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
       2: public class ExceptionPolicyAttribute: Attribute
       3: {
       4:     public string ExceptionPolicyName { get; private set; }
       5:     public ExceptionPolicyAttribute(string exceptionPolicyName)
       6:     {
       7:         this.ExceptionPolicyName = exceptionPolicyName;
       8:     }
       9: }

    別の方法GetHandleErrorActionNameは、Actionメソッドに適用される特性HandleErrorActionAttributeによって設定されたHandle-Error-Actionの名前を取得するために使用される.このプロパティは、アクションメソッドにもControllerクラスにも適用できるように定義されています.GetHandleErrorActionName法は,ControllerDescriptorとActionDescriptorを用いてアプリケーションのExceptionPolicyAttribute特性を得,最終的に対応する例外処理Action名を得る.
       1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method, AllowMultiple = false)]
       2: public class HandleErrorActionAttribute: Attribute
       3: {
       4:     public string HandleErrorAction { get; private set; }
       5:     public HandleErrorActionAttribute(string handleErrorAction = "")
       6:     {
       7:         this.HandleErrorAction = handleErrorAction;
       8:     }
       9: }

    HandleErrorActionAttributeプロパティで設定されたHandle-Error-Actionは、現在のリクエストに対する応答を実現するために手動で実行する必要があるため、以下のように定義されたHandleErrorActionInvokerを作成しました.これはControllerActionInvokerのサブクラスであり、Handle-Error-Actionは、現在のリクエストに対する応答の実行を仮想メソッドInvokeActionMethodによって達成するために手動で実行する必要がある.ExtendedControllerのHandleErrorActionInvokerは、このようなオブジェクトを返します.
       1: public class HandleErrorActionInvoker: ControllerActionInvoker
       2: {
       3:     public virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
       4:     {
       5:         IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
       6:         return base.InvokeActionMethod(controllerContext, actionDescriptor, parameterValues);
       7:     }
       8: }

    二、OnExceptionメソッドにおける異常処理ロジックの実現


    例外処理全体と最終的な要求に対する対応する実装は,以下に示すOnExceptionメソッドでは,プロセスは複雑ではなく,ここでは一つ一つ述べない.ただし、処理プロセス全体については、EntLibを呼び出すEHAB対例外処理中に、対応するExceptionHandlerが現在のHttpContextのItemsに保存されている友好的なエラーメッセージを設定できるようにする点が2つあります.2つ目は、例外処理方法を呼び出す前に、エラーメッセージを現在のModelStateに追加することです.これは、上記のインスタンスのプレゼンテーションでエラーメッセージがValidationSummaryに自動的に表示される理由の根本的な原因です.
       1: public class ExtendedController: Controller
       2: {    
       3:     //    
       4:     protected override void OnException(ExceptionContext filterContext)
       5:     {
       6:         //     ExceptionPolicy,     ,       OnException  
       7:         string exceptionPolicyName = this.GetExceptionPolicyName();
       8:         if (string.IsNullOrEmpty(exceptionPolicyName))
       9:         {
      10:             base.OnException(filterContext);
      11:             return;
      12:         }
      13:  
      14:         //  EntLib EHAB      ,               
      15:         filterContext.ExceptionHandled = true;
      16:         Exception exceptionToThrow;
      17:         string errorMessage;
      18:         try
      19:         {
      20:             ExceptionPolicy.HandleException(filterContext.Exception,exceptionPolicyName, out exceptionToThrow);
      21:             errorMessage = System.Web.HttpContext.Current.GetErrorMessage();
      22:         }
      23:         finally
      24:         {
      25:             System.Web.HttpContext.Current.ClearErrorMessage();
      26:         }
      27:         exceptionToThrow = exceptionToThrow ?? filterContext.Exception;
      28:  
      29:         //  Ajax  ,             JsonResult
      30:         if (Request.IsAjaxRequest())
      31:         {
      32:             filterContext.Result = Json(new ExceptionDetail(exceptionToThrow, errorMessage));
      33:             return;
      34:         }
      35:  
      36:         //        HandleErrorAction,    ;
      37:         //   Error View    
      38:         string handleErrorAction = this.GetHandleErrorActionName();
      39:         string controllerName = ControllerContext.RouteData.GetRequiredString("controller");
      40:         string actionName = ControllerContext.RouteData.GetRequiredString("action");
      41:         errorMessage = string.IsNullOrEmpty(errorMessage) ? exceptionToThrow.Message : errorMessage;
      42:         if (string.IsNullOrEmpty(handleErrorAction))
      43:         {
      44:             filterContext.Result = View("Error", new ExtendedHandleErrorInfo(exceptionToThrow, controllerName, actionName, errorMessage));
      45:         }
      46:         else
      47:         {
      48:             ActionDescriptor actionDescriptor = Descriptor.FindAction(ControllerContext, handleErrorAction);                
      49:             ModelState.AddModelError("", errorMessage);
      50:             filterContext.Result = this.HandleErrorActionInvoker.InvokeActionMethod(ControllerContext, actionDescriptor);
      51:         }
      52:     }      
      53: }

    三、処理後のエラーメッセージをHttpContextのItemsに保存する


    EntLibのEHABを呼び出して異常処理を行った後、現在のHttpContextからエラーメッセージを抽出し、最後のクリアメッセージは、それぞれHttpContextの拡張方法GetErrorMessageとClearErrorMessageによって実現される.次のコード・セグメントに示すように、この2つの拡張方法に加えて、エラー・メッセージを設定するためのもう1つのSetErrorMessage方法を定義します.
       1: public static class HttpContextExtensions
       2: {
       3:     public static string keyOfErrorMessage = Guid.NewGuid().ToString();
       4:  
       5:     public static void SetErrorMessage(this HttpContext context, string errorMessage)
       6:     {
       7:         context.Items[keyOfErrorMessage]=errorMessage;
       8:     }
       9:  
      10:     public static string GetErrorMessage(this HttpContext context)
      11:     {
      12:         return context.Items[keyOfErrorMessage] as string;
      13:     }
      14:  
      15:     public static void ClearErrorMessage(this HttpContext context)
      16:     {
      17:         if (context.Items.Contains(keyOfErrorMessage))
      18:         {
      19:             context.Items.Remove(keyOfErrorMessage);
      20:         }            
      21:     }
      22: }

    四、エラーメッセージを設定するためのErrorMessageHandler


    エラーメッセージを設定するためのErrorMessageHandlerと、対応する構成要素タイプのErrorMessageHandlerDataは、以下のように定義されています.ErrorMessageHandlerエラーメッセージを表すErrorMessage属性はコンストラクション関数で初期化され、実装されたHandleExceptionメソッドでは現在のHttpContextの拡張メソッドSetErrorMessageを呼び出すことによってエラーメッセージの設定が直接行われる.
       1: [ConfigurationElementType(typeof(ErrorMessageHandlerData))]
       2: public class ErrorMessageHandler: IExceptionHandler
       3: {
       4:     public string ErrorMessage { get; private set; }
       5:     public ErrorMessageHandler(string errorMessage)
       6:     {
       7:         this.ErrorMessage = errorMessage;
       8:     }
       9:     public Exception HandleException(Exception exception, Guid handlingInstanceId)
      10:     {
      11:         if (null != HttpContext.Current)
      12:         {
      13:             HttpContext.Current.SetErrorMessage(this.ErrorMessage);
      14:         }
      15:         return exception;
      16:     }
      17: }
      18:  
      19: public class ErrorMessageHandlerData : ExceptionHandlerData
      20: {
      21:     [ConfigurationProperty("errorMessage", IsRequired=true)]
      22:     public string ErrorMessage
      23:     {
      24:         get { return (string)this["errorMessage"]; }
      25:         set { this["errorMessage"] = value; }
      26:     }
      27:  
      28:     public override IEnumerable<TypeRegistration> GetRegistrations(string namePrefix)
      29:     {
      30:         yield return new TypeRegistration<IExceptionHandler>(() => new ErrorMessageHandler(this.ErrorMessage))
      31:         {
      32:             Name = this.BuildName(namePrefix),
      33:             Lifetime = TypeRegistrationLifetime.Transient
      34:         };
      35:     }
      36: }

     
    ASP.NET MVC統合EntLibによる「自動化」異常処理を実現[実例編]   ASP.NET MVC集積EntLib実現「自動化」異常処理[実現編]
    作成者:
    Artech
    出典:
    http://artech.cnblogs.com/
    本文の著作権は著者とブログ園に共有され、転載を歓迎するが、著者の同意を得ずにこの声明を保留し、文章のページの明らかな位置で原文の接続を与えなければならない.そうしないと、法律責任を追及する権利を保留する.
    分類:
    プログラミングテクニック
    フレーム設計