MVC filter Use Case: uniformly handling exceptions by streamlining code
1.MVC Filter
The idea of using attribute from Method 2 can easily think of the MVC filter, using the filter's interception function to implement exception handling in accordance with the AOP idea, and decouple the module from the logic layer. About the MVC filter introduction, many articles on the internet, recommended "MVC filter detailed". Here, the order of execution of the filter is emphasized.
General Filter Execution Order
Iauthorizationfilter->onauthorization (Authorized)
Iactionfilter->onactionexecuting (behavior)
Action
Iactionfilter->onactionexecuted (behavior)
Iresultfilter->onresultexecuting (Result)
View
Iresultfilter->onresultexecuted (Result)
*iexceptionfilter->onexception (Exception), this method is not executed in the order above, there is an exception occurs when the execution, a bit similar to the interrupt
When filters are set in both the Controller and the action, the order of execution is generally from outside to inside, i.e. "global", "Controller", "behavior"
Controller->iauthorizationfilter->onauthorization
Action->iauthorizationfilter->onauthorization
Controller->iactionfilter->onactionexecuting
Action->iactionfilter->onactionexecuting
Action
Action->iactionfilter->onactionexecuted
Controller->iactionfilter->onactionexecuted
Controller->iresultfilter->onresultexecuting
Action->iresultfilter->onactionexecuting
Action->iresultfilter->onactionexecuted
Controller->iresultfilter->onactionexecuted
Because the exception is thrown out from inside, because the order of the second exception is just the opposite, usually from inside to outside, that is, "behavior", "Controller", "global"
Action->iexceptionfilter->onexception
Controller->iexceptionfilter->onexception
Iv. system-brought exception handling
The filter we used to use is either adding attribute to the action or adding attribute to the controller. What's going on with the global filter mentioned above? First look at the code in Gloabal:
protected void Application_Start(){ //注册Area AreaRegistration.RegisterAllAreas(); //注册过滤器 RegisterGlobalFilters(GlobalFilters.Filters); //注册路由 RegisterRoutes(RouteTable.Routes);}public static void RegisterGlobalFilters(GlobalFilterCollection filters){ filters.Add(new HandleErrorAttribute());}
The
is known to have registered a global filter when the application is started, and Handleerrorattribute is the exception filter that comes with the system. In this registered global filter, you can not go to each controller or each action to declare, directly acting on the global, that is, you can catch all the exceptions of the entire site. See how its source code handles exceptions:
public virtual void Onexception (Exceptioncontext filtercontext) {if (Filtercontext = = null) {throw new ArgumentNullException ("Filtercontext"); } if (!filtercontext.ischildaction && (!filtercontext.exceptionhandled && Filtercontext.httpcon Text. iscustomerrorenabled)) {Exception innerexception = filtercontext.exception; if (new HttpException (null, innerexception). Gethttpcode () = = && this. Exceptiontype.isinstanceoftype (innerexception)) {String controllername = (string) filte rcontext.routedata.values["Controller"]; String actionname = (string) filtercontext.routedata.values["action"; Handleerrorinfo model = new Handleerrorinfo (filtercontext.exception, Controllername, ActionName); ViewResult result = new ViewResult {ViewName = this. View, Mastername = this. Master, ViewData = new viewdatadictionary
In Handleerrorattribute's exception handling logic, a model of the Handleerrorinfo class is generated and the returned result is set to a newly generated viewresult. The default viewname for this view is error, which corresponds to the error view in the share folder. The error view is not used in the Handleerrorinfo model, so the information disclosed is not many, can be modified according to the specific needs. For example:
View Code
This filter will work and need to be configured in the configuration file:
2. Custom exception Unification Processing
Before implementing the uniform processing of exceptions, make a clear request:
All pages in the site after the exception, you need to record the Exception log and turn to the error page (the level of detailed slightly of the exception is determined by the specific requirements)
All asynchronous requests that return JSON data require not only logging the Exception log, but also returning the JSON-formatted error message to the client instead of turning to the error page (the asynchronous request may not be able to turn to the error prompt page)
Using AOP to understand the decoupling of anomalies
Try to streamline the duplicate code that declares attribute
Implementations 1 and 3:
Because the Exception log is required for the entire site, it is necessary to design an exception logging filter (Logexceptionattribute) for interception, which embodies both the AOP idea and the need to understand the decoupling. The code is as follows:
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public class LogExceptionAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled) { string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; string msgTemplate = "在执行 controller[{0}] 的 action[{1}] 时产生异常"; LogManager.GetLogger("LogExceptionAttribute").Error(string.Format(msgTemplate, controllerName, actionName), filterContext.Exception); } base.OnException(filterContext); } }
Logexceptionattribute inherits the Handleerrorattribute, overriding the Onexception method after logging the exception log by calling base. Onexception back to the system default exception handling, the implementation of the error page to jump.
Logexceptionattribute set its own AttributeUsage feature, AttributeTargets.Class specifies that the filter can only be used for class one level, that is, controller;allowmultiple = False setting does not allow multiple executions, which are performed only once at the controller level.
Achieve
Obviously, because the requirements for logging the Exception Log are global, using a registered global filter will satisfy the need to streamline the code as much as possible. Add the following code when registering the filter Gloabal:
public static void RegisterGlobalFilters(GlobalFilterCollection filters){ filters.Add(new HandleErrorAttribute()); filters.Add(new LogExceptionAttribute());}
Implementation 2:
The error message returned in JSON format is not global, only required for certain actions, so it is necessary to design an exception filter that specifically returns the JSON information for the exception. This filter should only be used for action. According to the previous exception processing order, the principle of the first and the outside, in handling the exception, the JSON exception filter is processed first, and then processed the previously defined logexceptionattribute, so that the return of the JSON error message, and log the Exception log. The code is as follows:
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class JsonExceptionAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled) { //返回异常JSON filterContext.Result = new JsonResult { Data = new { Success = false, Message = filterContext.Exception.Message } }; } } }
A new Jsonresult object is generated in the Jsonexceptionattribute and assigned to the return result (and, of course, it is also necessary to unify the JSON return format for the entire site) At the same time, it is specified by AttributeTargets.Method that the filter can only be used at the method level, which corresponds to action.
It is important to note that you do not need to call base. Onexception, otherwise it skips Logexceptionattribute first to execute Handleerrorattribute's processing logic, thus returning the result is no longer jsonresult, but Viewresult, The client will not be able to handle non-JSON results.
There is also no need to set filtercontext.exceptionhandled = True, otherwise in logexceptionattribute processing, because the!filtercontext.exceptionhandled judgment condition , the Logexceptionattribute logic does not execute, and the exception log is not logged.
When used, you only need to declare this feature on the action. The code is as follows:
[HttpPost][JsonException]public JsonResult Add(string ip, int port){ ... //处理逻辑 return Json(new { Success = true, Message = "添加成功" });}
In order to cope with the normal operation of Jsonexceptionattribute, Logexceptionattribute also need to make corresponding changes:
[AttributeUsage (AttributeTargets.Class, inherited = True, AllowMultiple = False)] public Class Logexceptionattribute: Handleerrorattribute {public override void Onexception (Exceptioncontext filtercontext) {if ( !filtercontext.exceptionhandled) {String controllername = (string) filterContext.RouteData.Value s["Controller"]; String actionname = (string) filtercontext.routedata.values["action"; String msgtemplate = "An exception occurred while executing controller[{0}] action[{1}]"; Logmanager.getlogger ("Logexceptionattribute"). Error (String. Format (Msgtemplate, Controllername, ActionName), filtercontext.exception); if (Filtercontext.result is Jsonresult) {//When the result is JSON, the set exception has been processed by the filter Context.exceptionhandled = true; } else {//otherwise calls the original set base. Onexception (Filtercontext); } } }
Note Before and after comparison, in the Logexceptionattribute will not directly call Base.onexception, but first to determine whether the current return is not jsonresult. The returned result is Jsonresult, which indicates that the Jsonexceptionattribute was previously processed and that the setting filtercontext.exceptionhandled = True is required. And does not continue the processing of base class Handleerrorattribute; The return result is not jsonresult, then base is called. Onexception, continue to execute the logic of the base class Handleerrorattribute and turn to the error page.
If you need to extend other types of exception handling, you only need to add the corresponding exception filter, and the corresponding transformation in the Logexceptionattribute.
3. PostScript
Adding the above filter and changing it with the configuration file, our exception handling a few requirements are complete. If there is not much change, such a processing mode can be common to the MVC site. In this mode, if there is no special need, in our controller, logic layer, data access layer, etc., there is no need to add additional exception handling code, resulting in an exception after the direct extrapolation, will eventually be blocked by the exception filter and processed.
Even for specific requirements, it may be necessary to catch and handle some code blocks with try{}catch{}, and it is also recommended that the throw statement be used to throw exceptions after processing in the catch statement. Unified by the Logexceptionattribute to carry out the final capture and processing. This will massively reduce the repetition of the try{}catch{} statement. Of course, the specifics of how the exception is handled will be adjusted as appropriate.
Transferred from: http://www.cnblogs.com/Showshare/p/exception-handle-with-mvcfilter.html
MVC filter Use Case: uniformly handling exceptions by streamlining code