Summary of complete solutions based on Exception Handling under ASP. net mvc, and complete mvc Solutions

Source: Internet
Author: User

Summary of complete solutions based on Exception Handling under ASP. net mvc, and complete mvc Solutions

The Exception Handling Application Block of EntLib is a good framework for Exception Handling. It allows us to define an Exception Handling policy in configuration mode. ASP. net mvc is a highly scalable development framework. In this article, I will integrate with EntLib through its extension, and provide a complete solution for exception handling.

I. Basic exception handling policies

First, we will discuss the specific exception handling policies adopted by our solution:

For exceptions thrown by executing an Action Method of the Controller, we will handle the exceptions according to the specified Configuration Policy. We can take log records, replace exceptions, and encapsulate these common exception handling methods;

For an exception after processing, if the exception handling policy requires that it be thrown, the error page that matches the exception type is automatically redirected. We maintain a matching relationship between the exception type and Error View;

If the exception handling policy does not need to throw the exception after processing, an error handling Action that matches the current Action is executed. By default, the Action Method of exception handling adopts a naming rule such as "On {Action} Error", and the current context is bound to the parameters of the Action Method of exception handling. In addition to the number of times, we will set the current ModelState error message;

If the user does not define the corresponding exception handling Action, the "error page redirection" method is still used for exception handling.

Ii. Handling exceptions through custom actions

To give readers a deep understanding of the exception handling page described above, let's take an example. This instance is used to simulate user logon. For example, we define the next Model, LoginInfoModel, which contains only the username and password attributes.

  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; }    }  }

We have defined the next AccountController as a subclass of our custom BaseController. When constructing the account controller, the parameter specified by the base class constructor is called to represent the configuration name of the exception handling policy. The SignIn method indicates the operation used for "Logon", while OnSignInError indicates the exception handling operation corresponding to this operation. If the exception thrown in the SignIn operation does not need to be thrown after processing, OnSignInError is called, and the ModelState has been set with the corresponding error message.

  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 });    }  }

The authentication logic defined in the SignIn operation method is as follows: if the user name is not "Foo", an InvalidUserNameException exception is thrown; if the password is not "password", a UserNamePasswordNotMatchException is thrown. The following is the definition of the View corresponding to the SignIn operation:

  @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" />  }

The exception handling policy "myPolicy" specified during AccountController Initialization is defined in the following configuration. We specifically handle the InvalidUserNameException and UserNamePasswordNotMatchException thrown by the SignIn operation method, while ErrorMessageSettingHandler is our custom exception processor, which is only used to set error messages. As shown in the following code snippet, if these two types of exceptions are thrown, the final error message will be specified as "User name does not exist !" And "User name does not match password !".

  <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>

Now we can set AccountController and Sign as default Controller and Action through routing ing, and then enable our application. When you enter the wrong user name and error code, the system will automatically receive the corresponding error message in ValidationSummary.

3. handle exceptions through the configured Error View

In the preceding configuration, all configuration policies for InvalidUserNameException and UserNamePasswordNotMatchException set the PostHandlingAction attribute to "None ", this means that the original exception and the processed exception will not be thrown again. Now we set this attribute to "ThrowNewException", which means we will throw the processed exception again.

  <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>

According to our above exception handling policy, in this case, we will use the "error page" Method for exception handling. The HandleErrorAttribute processing method is similar. We support the matching relationship between the exception type and Error View, which is defined by the following configuration. It is worth mentioning that the exception type here is the exception that is thrown again after processing.

  <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>

As shown in the preceding configuration, we define different Error views for InvalidUserNameException and UserNamePasswordNotMatchException, which are "InvalideUserNameError" and "UserNamePasswordNotMatchError". The detailed definitions are as follows:

  @{     Layout = null;   }   <!DOCTYPE html>   

Now we run our program in the above way. When the wrong user name and password are entered separately, the corresponding error page is displayed automatically.

4. Custom ActionInvoker: ExceptionActionInvoker

The preceding two different exception handling methods are implemented through the custom ActionInvoker. We name them predictionactioninvoker. As shown in the following code snippet, predictionactioninvoker directly inherits from ControllerActionInvoker. The ExceptionPolicy attribute is a ExceptionPolicyImpl object created based on the specified exception policy name. It is used for exception handling on EntLib. The attribute GetErrorView is a delegate used to obtain the ViewResult object as the error page. The core definition of exception handling is in the InvokeAction method. The handleErrorActionName parameter specified in this method represents the "Exception Handling Operation name". The entire method is implemented according to the preceding Exception Handling Policy.

  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";        }      }    }  }

5. Custom Controller: BaseController

ExceptionActionInvoker is finally called in our custom Controller base class BaseController. The ExceptionActionInvoker object is initialized in the constructor and called in the override OnException method.

  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);          }        }      }    }  }

It is worth mentioning that all the operations in the OnException method are performed in a ExceptionHandlingContextScope. As the name suggests, we use predictionhandlingcontextscope to create a range for predictionhandlingcontext. Predictionhandlingcontext is defined as follows. We can use it to obtain the Current predictioncontext and ModelErrorCollection, while the static property Current returns the Current predictionhandlingcontext object.

  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; }    }  }

In the OnException method of BaseController, when the InvokeAction of ExceptionActionInvoker is executed, we will transfer the ModelError of the current ExceptionHandlingContext to the current ModelState. This is why the error message is displayed through ValidationSummary. In our example, the error message is specified through the ErrorMessageSettingHandler shown below, and it only adds the specified error message to the Errors attribute set of the current ExceptionHandlingContext.

  [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;    }  } 

Source code download from here: http://xiazai.jb51.net/201701/yuanma/ExceptionHandling_jb51.rar

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.