Heim  >  Artikel  >  Backend-Entwicklung  >  Zusammenfassung der ASP.NET MVC-Lösungen zur Ausnahmebehandlung

Zusammenfassung der ASP.NET MVC-Lösungen zur Ausnahmebehandlung

巴扎黑
巴扎黑Original
2017-08-16 16:16:361495Durchsuche

ASP.NET MVC ist ein sehr erweiterbares Entwicklungsframework. In diesem Artikel werde ich es über seine Erweiterung in EntLib integrieren und eine vollständige Lösung für die Ausnahmebehandlung bereitstellen.

Der Ausnahmebehandlungs-Anwendungsblock von EntLib ist ein gutes Ausnahmebehandlungs-Framework, das es uns ermöglicht, Ausnahmebehandlungsstrategien durch Konfiguration zu definieren. ASP.NET MVC ist ein sehr erweiterbares Entwicklungsframework. In diesem Artikel werde ich es über seine Erweiterung in EntLib integrieren und eine vollständige Ausnahmebehandlungslösung bereitstellen.

1. Grundlegende Ausnahmebehandlungsstrategie

Besprechen wir zunächst die spezifische Ausnahmebehandlungsstrategie unserer Lösung:

Bei Ausnahmen, die durch die Ausführung einer Aktionsmethode des Controllers ausgelöst werden, behandeln wir sie gemäß der angegebenen Konfigurationsstrategie. Wir können gängige Ausnahmebehandlungsmethoden wie Protokollierung, Ausnahmeersetzung und Kapselung übernehmen.

Wenn die Ausnahmebehandlungsrichtlinie vorschreibt, dass sie ausgelöst werden müssen, werden sie automatisch zur Fehlerseite weitergeleitet passender Ausnahmetyp. Wir pflegen eine übereinstimmende Beziehung zwischen dem Ausnahmetyp und der Fehleransicht.

Wenn die Ausnahmebehandlungsrichtlinie vorschreibt, dass sie nicht ausgelöst werden muss, entspricht dies einer Operation, die mit der aktuellen Aktion übereinstimmt Die Fehlerbehandlungsaktion wird zur Behandlung des Fehlers verwendet. Die Aktionsmethode zur Ausnahmebehandlung verwendet standardmäßig die Benennungsregel „On{Action}Error“, und der aktuelle Kontext wird an die Parameter der Aktionsmethode zur Ausnahmebehandlung gebunden. Darüber hinaus legen wir die Fehlerinformationen des aktuellen ModelState fest;

Wenn der Benutzer die entsprechende Ausnahmebehandlungsaktion nicht definiert hat, wird die Methode „Fehlerseitenumleitung“ weiterhin für die Ausnahmebehandlung verwendet.

2. Ausnahmebehandlung durch benutzerdefinierte Aktionen

Um den Lesern ein tiefes Verständnis der oben vorgestellten Ausnahmebehandlungsseite zu vermitteln, führen wir eine durch Beispieldemonstration. Diese Instanz wird verwendet, um die Benutzeranmeldung zu simulieren. Wir definieren das folgende Modell, das nur zwei Attribute enthält: Benutzername und Passwort: LoginInfoModel.


  namespace Artech.Mvc.ExceptionHandling.Models
   {
     public class LoginInfo
     {
       [Display(Name ="User Name")]
       [Required(ErrorMessage = "User Name is manadatory!")]
       public string UserName { get; set; }
   
       [Display(Name = "Password")]
      [DataType(DataType.Password)]
      [Required(ErrorMessage = "Password is manadatory!")]
      public string Password { get; set; }
    }
  }

Wir definieren den folgenden AccountController, der eine Unterklasse unseres benutzerdefinierten BaseControllers ist. Wenn AccountController während der Erstellung den Basisklassenkonstruktor aufruft, stellen die angegebenen Parameter den Konfigurationsnamen der Ausnahmebehandlungsstrategie dar. Die SignIn-Methode stellt den Vorgang „Anmelden“ dar, und OnSignInError stellt den dem Vorgang entsprechenden Ausnahmebehandlungsvorgang dar. Wenn die im SignIn-Vorgang ausgelöste Ausnahme behandelt wird und nicht mehr ausgelöst werden muss, wird OnSignInError aufgerufen und der ModelState wurde mit der entsprechenden Fehlermeldung festgelegt.


  public class AccountController BaseController
   {
     public AccountController()
       base("myPolicy")
     { }
   
     public ActionResult SignIn()
     {
       return View(new LoginInfo());
    }
    [HttpPost]
    public ActionResult SignIn(LoginInfo loginInfo)
    {
      if (!ModelState.IsValid)
      {
        return this.View(new LoginInfo { UserName = loginInfo.UserName });
      }
   
      if (loginInfo.UserName != "Foo")
      {
        throw new InvalidUserNameException();
      }
   
      if (loginInfo.Password != "password")
      {
        throw new UserNamePasswordNotMatchException();
      }
   
      ViewBag.Message = "Authentication Succeeds!";
      return this.View(new LoginInfo { UserName = loginInfo.UserName });
    }
   
    public ActionResult OnSignInError(string userName)
    {
      return this.View(new LoginInfo { UserName = userName });
    }
  }

Die in der SignIn-Operationsmethode speziell definierte Authentifizierungslogik lautet wie folgt: Wenn der Benutzername nicht „Foo“ ist, wird eine InvalidUserNameException ausgelöst „Passwort ist nicht „Passwort““ löst eine UserNamePasswordNotMatchException-Ausnahme aus. Im Folgenden finden Sie die Definition der Ansicht, die dem Anmeldevorgang entspricht:


  @model Artech.Mvc.ExceptionHandling.Models.LoginInfo
   @{
     ViewBag.Title = "SignIn";
   }
   @Html.ValidationSummary()
   @if (ViewBag.Messages != null)
   { 
     @ViewBag.Messages
   }
  @using (Html.BeginForm())
  { 
    @Html.EditorForModel()
    <input type="submit" value="SignIn" />
  }

Die bei der Initialisierung des AccountControllers angegebene Ausnahmebehandlungsrichtlinie „myPolicy“ wird im Folgenden definiert Konfiguration. Wir behandeln speziell die von der SignIn-Operationsmethode ausgelösten InvalidUserNameException und UserNamePasswordNotMatchException, und der ErrorMessageSettingHandler ist unser benutzerdefinierter Ausnahmehandler, der nur zum Festlegen der Fehlermeldung verwendet wird. Wie im folgenden Codeausschnitt gezeigt, werden beim Auslösen der beiden oben genannten Ausnahmetypen die endgültigen Fehlermeldungen als „Benutzername existiert nicht!“ und „Benutzername stimmt nicht mit Passwort überein!“ angegeben.


  <exceptionHandling>
    <exceptionPolicies>
     <add name="myPolicy">
      <exceptionTypes>
       <add name="InvalidUserNameException" 
          type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling"
         postHandlingAction="None">
        <exceptionHandlers>
         <add name="ErrorMessageSettingHandler"
           type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling"
           errorMessage="User name does not exist!"/>
       </exceptionHandlers>
      </add>
      <add name="UserNamePasswordNotMatchException" 
          type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling"
         postHandlingAction="None">
       <exceptionHandlers>
        <add name="ErrorMessageSettingHandler"
           type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling"
           errorMessage="User name does not match password!"/>
       </exceptionHandlers>
      </add>     
     </exceptionTypes>
    </add>
   </exceptionPolicies>
  </exceptionHandling>

Jetzt legen wir AccountController und Sign über die Routenzuordnung als Standard-Controller und -Aktion fest und starten unsere Anwendung. Wenn Sie einen falschen Benutzernamen und ein falsches Passwort eingeben, erhalten Sie automatisch die entsprechende Fehlermeldung in der ValidationSummary.

3. Behandlung von Ausnahmen über die konfigurierte Fehleransicht

In der obigen Konfiguration für die beiden Ausnahmen InvalidUserNameException und UserNamePasswordNotMatchException Die Konfiguration Die Strategie des Typs setzt das PostHandlingAction-Attribut auf „None“, was bedeutet, dass die ursprüngliche Ausnahme und die behandelte Ausnahme nicht erneut ausgelöst werden. Jetzt setzen wir diese Eigenschaft auf „ThrowNewException“, was bedeutet, dass wir die behandelte Ausnahme erneut auslösen.


  <exceptionHandling>
    <exceptionPolicies>
     <add name="myPolicy">
      <exceptionTypes>
       <add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling"
         postHandlingAction="ThrowNewException">
       ...
       <add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling"
         postHandlingAction="ThrowNewException">
       ...
      </add>     
     </exceptionTypes>
    </add>
   </exceptionPolicies>
  </exceptionHandling>

Gemäß unserer oben genannten Ausnahmebehandlungsstrategie verwenden wir in diesem Fall die Methode „Fehlerseite“ zur Ausnahmebehandlung. HandleErrorAttribute wird ebenfalls auf ähnliche Weise gehandhabt. Wir unterstützen die Übereinstimmungsbeziehung zwischen Ausnahmetypen und Fehleransichten, die durch eine Konfiguration ähnlich der folgenden definiert wird. Es ist erwähnenswert, dass der Ausnahmetyp hier eine Ausnahme ist, die nach der Behandlung erneut ausgelöst wird.


  <artech.exceptionHandling>
    <add exceptionType="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling"
       errorView="InvalideUserNameError"/>
    <add exceptionType="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling"
       errorView="UserNamePasswordNotMatchError"/>
   </artech.exceptionHandling>

Wie in der obigen Konfiguration gezeigt, haben wir unterschiedliche Fehleransichten für die beiden Ausnahmetypen InvalidUserNameException und UserNamePasswordNotMatchException definiert, nämlich „InvalideUserNameError“ und „UserNamePasswordNotMatchError“. , die detaillierte Definition lautet wie folgt:


  @{
     Layout = null;
   }
   <!DOCTYPE html>
   <html>
   <head>
     <title>Error</title>
   </head>
   <body>
    <p style="colorRed; font-weightbold">Sorry,the user name you specify does not exist!</p>
  </body>
  </html>
   
  @{
    Layout = null;
  }
  <!DOCTYPE html>
  <html>
  <head>
    <title>Error</title>
  </head>
  <body>
    <p style="colorRed; font-weightbold">Sorry, The password does not match the given user name!</p>
  </body>
  </html>

现在我们按照上面的方式运行我们的程序,在分别输入错误的用户名和密码的情况下会自动显现相应的错误页面。

四、自定义ActionInvoker:ExceptionActionInvoker

对于上述的两种不同的异常处理方式最终是通过自定义的ActionInvoker来实现的,我们将其命名为ExceptionActionInvoker。如下面的代码片断所式,ExceptionActionInvoker直接继承自ControllerActionInvoker。属性ExceptionPolicy是一个基于指定的异常策略名称创建的ExceptionPolicyImpl 对象,用于针对EntLib进行的异常处理。而属性GetErrorView是一个用于获得作为错误页面的ViewResult对象的委托。整个异常处理的核心定义在InvokeAction方法中,该方法中指定的handleErrorActionName参数代表的是“异常处理操作名称”,整个方法就是按照上述的异常处理策略实现的。


  using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Web;
   using System.Web.Mvc;
   using Artech.Mvc.ExceptionHandling.Configuration;
   using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
   using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
   namespace Artech.Mvc.ExceptionHandling
  {
    public class ExceptionActionInvoker ControllerActionInvoker
    {
      protected ExceptionHandlingSettings ExceptionHandlingSettings{get; private set;}
      protected virtual Func<string, HandleErrorInfo, ViewResult> GetErrorView { get; private set; }
      public ExceptionPolicyImpl ExceptionPolicy { get; private set; }
      public ExceptionActionInvoker(string exceptionPolicy,Func<string, HandleErrorInfo, ViewResult> getErrorView)
      {
        this.ExceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicy);
        this.GetErrorView = getErrorView;
        this.ExceptionHandlingSettings = ExceptionHandlingSettings.GetSection();
      }
   
      public override bool InvokeAction(ControllerContext controllerContext, string handleErrorActionName)
      {
        ExceptionContext exceptionContext = controllerContext as ExceptionContext;
        if (null == exceptionContext)
        {
          throw new ArgumentException("The controllerContext must be ExceptionContext!", "controllerContext");
        }
        try
        {
          exceptionContext.ExceptionHandled = true;
          if (this.ExceptionPolicy.HandleException(exceptionContext.Exception))
          {
            HandleRethrownException(exceptionContext);
          }
          else
          {
            if (ExceptionHandlingContext.Current.Errors.Count == 0)
            {
              ExceptionHandlingContext.Current.Errors.Add(exceptionContext.Exception.Message);
            }
            ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(exceptionContext);
            ActionDescriptor handleErrorAction = FindAction(exceptionContext, controllerDescriptor, handleErrorActionName);
            if (null != handleErrorAction)
            {
              IDictionary<string, object> parameters = GetParameterValues(controllerContext, handleErrorAction);
              exceptionContext.Result = this.InvokeActionMethod(exceptionContext, handleErrorAction, parameters);
            }
            else
            {
              HandleRethrownException(exceptionContext);
            }
          }
          return true;
        }
        catch (Exception ex)
        {
          exceptionContext.Exception = ex;
          HandleRethrownException(exceptionContext);
          return true;
        }
      }
      protected virtual void HandleRethrownException(ExceptionContext exceptionContext)
      {
        string errorViewName = this.GetErrorViewName(exceptionContext.Exception.GetType());
        string controllerName = (string)exceptionContext.RouteData.GetRequiredString("controller");
        string action = (string)exceptionContext.RouteData.GetRequiredString("action");
        HandleErrorInfo handleErrorInfo = new HandleErrorInfo(exceptionContext.Exception, controllerName, action);
        exceptionContext.Result = this.GetErrorView(errorViewName, handleErrorInfo);
      }
      protected string GetErrorViewName(Type exceptionType)
      {
        ExceptionErrorViewElement element = ExceptionHandlingSettings.ExceptionErrorViews
          .Cast<ExceptionErrorViewElement>().FirstOrDefault(el=>el.ExceptionType == exceptionType);
        if(null != element)
        {
          return element.ErrorView;
        }
        if(null== element && null != exceptionType.BaseType!= null)
        {
          return GetErrorViewName(exceptionType.BaseType);
        }
        else
        {
          return "Error";
        }
      }
    }
  }

五、自定义Controller:BaseController

ExceptionActionInvoker最终在我们自定义的Controller基类BaseController中被调用的。ExceptionActionInvoker对象在构造函数中被初始化,并在重写的OnException方法中被调用。


  using System;
   using System.Web.Mvc;
   namespace Artech.Mvc.ExceptionHandling
   {
     public abstract class BaseController Controller
     {
       public BaseController(string exceptionPolicy)
       {
         Func<string, HandleErrorInfo, ViewResult> getErrorView = (viewName, handleErrorInfo) => this.View(viewName, handleErrorInfo);
        this.ExceptionActionInvoker = new ExceptionActionInvoker(exceptionPolicy,getErrorView);
      }
      public BaseController(ExceptionActionInvoker actionInvoker)
      {
        this.ExceptionActionInvoker = actionInvoker;
      }
   
      public virtual ExceptionActionInvoker ExceptionActionInvoker { get; private set; }
   
      protected virtual string GetHandleErrorActionName(string actionName)
      {
        return string.Format("On{0}Error", actionName);
      }
   
      protected override void OnException(ExceptionContext filterContext)
      {
        using (ExceptionHandlingContextScope contextScope = new ExceptionHandlingContextScope(filterContext))
        {
          string actionName = RouteData.GetRequiredString("action");
          string handleErrorActionName = this.GetHandleErrorActionName(actionName);
          this.ExceptionActionInvoker.InvokeAction(filterContext, handleErrorActionName);
          foreach (var error in ExceptionHandlingContext.Current.Errors)
          {
            ModelState.AddModelError(Guid.NewGuid().ToString() ,error.ErrorMessage);
          }
        }
      }
    }
  }

值得一提的是:整个OnException方法中的操作都在一个ExceptionHandlingContextScope中进行的。顾名思义, 我们通过ExceptionHandlingContextScope为ExceptionHandlingContext创建了一个范围。ExceptionHandlingContext定义如下,我们可以通过它获得当前的ExceptionContext和ModelErrorCollection,而静态属性Current返回当前的ExceptionHandlingContext对象。


  public class ExceptionHandlingContext
   {
     [ThreadStatic]
     private static ExceptionHandlingContext current;
   
     public ExceptionContext ExceptionContext { get; private set; }
     public ModelErrorCollection Errors { get; private set; }
   
     public ExceptionHandlingContext(ExceptionContext exceptionContext)
    {
      this.ExceptionContext = exceptionContext;
      this.Errors = new ModelErrorCollection();
    }
    public static ExceptionHandlingContext Current
    {
      get { return current; }
      set { current = value; }
    }
  }

在BaseController的OnException方法中,当执行了ExceptionActionInvoker的InvokeAction之后,我们会将当前ExceptionHandlingContext的ModelError转移到当前的ModelState中。这就是为什么我们会通过ValidationSummary显示错误信息的原因。对于我们的例子来说,错误消息的指定是通过如下所示的ErrorMessageSettingHandler 实现的,而它仅仅将指定的错误消息添加到当前ExceptionHandlingContext的Errors属性集合中而已。


  [ConfigurationElementType(typeof(ErrorMessageSettingHandlerData))]
   public class ErrorMessageSettingHandler IExceptionHandler
   {
     public string ErrorMessage { get; private set; }
     public ErrorMessageSettingHandler(string errorMessage)
     {
       thisErrorMessage = errorMessage;
     }
     public Exception HandleException(Exception exception, Guid handlingInstanceId)
    {
      if (null == ExceptionHandlingContextCurrent)
      {
        throw new InvalidOperationException("");
      }
   
      if (stringIsNullOrEmpty(thisErrorMessage))
      {
        ExceptionHandlingContextCurrentErrorsAdd(exceptionMessage);
      }
      else
      {
        ExceptionHandlingContextCurrentErrorsAdd(thisErrorMessage);
      }
      return exception;
    }
  }

Das obige ist der detaillierte Inhalt vonZusammenfassung der ASP.NET MVC-Lösungen zur Ausnahmebehandlung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn