In webform, the process of validation is roughly as follows:
In AOP:
In Filter:
AuthorizeAttribute permission validation
After login, you have the right to control. Some pages need user login to access. You need to add a validation to the visiting pages, and you can't use every action once.
1. Write a Custom Authorization Attribute, inherit from Authorization Attribute, rewrite the OnAuthorization method, and write the logic as its own.
2. Method registration and controller registration.
3. With global registration, all action s of the controllers are in effect.
But in this, first of all, to verify the login home page, the home page does not have Deng Li, ran to the login page, but the login page also has to follow the logic in the features, and redirect to Deng Li... The cycle...
Here's an AlloAnonymous tag. This tag can solve the problem of this loop. Anonymous support does not require login, but it's useless to add features alone. In fact, it's also possible to support verification, even to customize a feature. This feature is empty, just for use. Make a mark.
The scope of use of features, we hope that the characteristics are universal, in different systems, different address login, =="add a parameter constructor on the features.
public class CustomAllowAnonymousAttribute : Attribute { }
CustomAuthorAttribute class
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class CustomAuthorizeAttribute : AuthorizeAttribute { private Logger logger = new Logger(typeof(CustomAuthorizeAttribute)); private string _LoginUrl = null; public CustomAuthorizeAttribute(string loginUrl = "~/Home/Login") { this._LoginUrl = loginUrl; } //public CustomAuthorizeAttribute(ICompanyUserService service) //{ //} //No way public override void OnAuthorization(AuthorizationContext filterContext) { var httpContext = filterContext.HttpContext;//Can get httpcontext You can do whatever you want. if (filterContext.ActionDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true)) { return; } else if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true)) { return; } else if (httpContext.Session["CurrentUser"] == null || !(httpContext.Session["CurrentUser"] is CurrentUser))//It's empty. { //Here's the user. With the address, you can actually check the permissions. if (httpContext.Request.IsAjaxRequest()) //httpContext.Request.Headers["xxx"].Equals("XMLHttpRequst") { filterContext.Result = new NewtonJsonResult( new AjaxResult() { Result = DoResult.OverTime, DebugMessage = "Landing overdue", RetValue = "" }); } else { httpContext.Session["CurrentUrl"] = httpContext.Request.Url.AbsoluteUri; filterContext.Result = new RedirectResult(this._LoginUrl); //Shorter: specified Result,Then the request is closed and will not be executed. action } } else { CurrentUser user = (CurrentUser)httpContext.Session["CurrentUser"]; //this.logger.Info($"{user.Name}Logged on to the system"); return;//Continue } //base.OnAuthorization(filterContext); } }
Filter Effective Mechanism
Why add a tag, inherit AuthorizeAttribute, and rewrite the OnAuthorization method? Controller has been instantiated, call ExecuteCore method, find method name, Controller Action Invokee. InvokeAction, find all Filter features, InvokeAuthorize - result is not empty, direct InvokeAction Result, empty normal execution of action.
There is an instance type and a method name that you want to reflect on.
After finding the method, before executing the method, the characteristics can be detected, from the global, from the controller, from the method. Spread characteristics, characteristics are predefined by themselves, according to class implementation, set a logo, as empty as normal, not empty jump, normal continue to implement.
Filter Principle and AOP Face-Oriented Programming
Filter is an implementation of AOP. In fact, there is an InvokeAction method in the ControllerActionInvoke class. After controller instantiation, before and after ActionInvoke, AOP is achieved by detecting predefined filter and executing it.
Here is the source code for InvokeAction:
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch()) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName"); } ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext); ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName); if (actionDescriptor != null) { FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor); try { AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor); if (authenticationContext.Result != null) { AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result); this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result); } else { AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor); if (authorizationContext.Result != null) { AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result); this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result); } else { if (controllerContext.Controller.ValidateRequest) { ControllerActionInvoker.ValidateRequest(controllerContext); } IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor); ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues); AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result); this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result); } } } catch (ThreadAbortException) { throw; } catch (Exception exception) { ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception); if (!exceptionContext.ExceptionHandled) { throw; } this.InvokeActionResult(controllerContext, exceptionContext.Result); } return true; } return false; }
HandleErrorAttribute for Global Exception Handling
Suggestions on exception handling:
1. Avoid the UI layer seeing exceptions directly, try-catch in each controller? Isn't it too much trouble?
2. At this time, AOP comes on the scene. HandleErrorAttribute writes its own feature, inherits HandleErrorAttribute, rewrites OnException, and jumps to this method after an exception occurs.
On this side, we must
public class CustomHandleErrorAttribute : HandleErrorAttribute { private Logger logger = new Logger(typeof(CustomHandleErrorAttribute)); /// <summary> /// After the exception occurs, jump to this method /// </summary> /// <param name="filterContext"></param> public override void OnException(ExceptionContext filterContext) { var httpContext = filterContext.HttpContext;//"Do as one pleases" if (!filterContext.ExceptionHandled)//No other HandleErrorAttribute Handle { this.logger.Error($"In response {httpContext.Request.Url.AbsoluteUri} When an exception occurs, information:{filterContext.Exception.Message}");// if (httpContext.Request.IsAjaxRequest()) { filterContext.Result = new NewtonJsonResult( new AjaxResult() { Result = DoResult.Failed, DebugMessage = filterContext.Exception.Message, RetValue = "", PromptMsg = "An error occurred. Please contact the administrator." }); } else { filterContext.Result = new ViewResult()//Short circuiting device { ViewName = "~/Views/Shared/Error.cshtml", ViewData = new ViewDataDictionary<string>(filterContext.Exception.Message) }; } filterContext.ExceptionHandled = true;//It's been dealt with by me. } } }
This is the address to be redirected:
Be sure to consider whether Ajax requests
Can you enter custom exceptions in a variety of exceptions?
1. Action exception, not Catch
2. Action exception, Catch
3. Action calls Service exceptions
4. Action Normal View Abnormal
5. Controller construction is abnormal
6. Action name error
7. Arbitrary Address Error
8. Permission Filter exception
Answer:
1.
2. No
3. Yes, abnormal bubbling
4. Yes, why? Because Execute Result is wrapped in try
5. No. Filter is done before the method executes after the control is constructed.
6. No, because requests do not enter the MVC process.
7. No, because requests are not entered into MVC
8. Yes, the permission Filter is also in try.
What about these uncovered anomalies? There's another way.
Add an event to Global
public class MvcApplication : System.Web.HttpApplication { private Logger logger = new Logger(typeof(MvcApplication)); protected void Application_Start() { AreaRegistration.RegisterAllAreas();//Registering area FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//Registered Global Filter RouteConfig.RegisterRoutes(RouteTable.Routes);//Registration routing BundleConfig.RegisterBundles(BundleTable.Bundles);//Merge Compression, Packaging Tool Combres ControllerBuilder.Current.SetControllerFactory(new ElevenControllerFactory()); this.logger.Info("The website is launched..."); } /// <summary> /// Global exception handling can catch the fish out of the net /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_Error(object sender, EventArgs e) { Exception excetion = Server.GetLastError(); this.logger.Error($"{base.Context.Request.Url.AbsoluteUri}Abnormal"); Response.Write("System is Error...."); Server.ClearError(); //Response.Redirect //base.Context.RewritePath("/Home/Error?msg=") }
Handle ErrorAttribute + Application_Error, with different granularity, can get different things
IActionFilter Extended Customization
IActionFilter
1. Before the OnAction Executing method is executed
2. After the OnActionExecuted method is executed
3. Before the OnResultExecuting result is executed
4. After the OnResultExecuted result is executed
Execute the permission Filter first, then the ActionFilter.
Order of execution:
Global OnActionExecuting
Controller OnActionExecuting
Action OnActionExecuting
Action True Execution
Action OnActionExecuted
Controller OnActionExecuted
Global OnActionExecuted
Effective Order of Registration at Different Locations: Global -"Controller -" Action
It's like a Russian doll, or onion model.
In the order of registration in the same location, the same location will take effect in the order in which it is registered. There is also a parameter of Order, which does not set the default of Order 1. After setting, it will be executed from small to large.
What can ActionFilter do?
Logging, parameter detection, caching, rewriting view, compression, anti-theft chain, statistical access, different clients jump different pages, current limit...
When the browser requests, it will declare the supported format. The default IIS is not compressed. It detects the supported format, compresses the data in response (completed by the IIS server), adds Content-Encoding to the response header. The browser looks at the data format and decompresses it according to the browser format (whatever you are, all of them are decompressed according to the browser format). Compression can be decompressed), compression is IIS, decompression is browser.
public class CompressActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { //foreach (var item in filterContext.ActionParameters) //{ // //Sensitive Word Filtering for Parameter Detection //} var request = filterContext.HttpContext.Request; var respose = filterContext.HttpContext.Response; string acceptEncoding = request.Headers["Accept-Encoding"];//Detection Support Format if (!string.IsNullOrWhiteSpace(acceptEncoding) && acceptEncoding.ToUpper().Contains("GZIP")) { respose.AddHeader("Content-Encoding", "gzip");//Response header specifies type respose.Filter = new GZipStream(respose.Filter, CompressionMode.Compress);//Compression type specification } } } public class LimitActionFilterAttribute : ActionFilterAttribute { private int _Max = 0; public LimitActionFilterAttribute(int max = 1000) { this._Max = max; } public override void OnActionExecuting(ActionExecutingContext filterContext) { string key = $"{filterContext.RouteData.Values["Controller"]}_{filterContext.RouteData.Values["Action"]}"; //CacheManager.Add(key,) Cache to cache key Collection time filterContext.Result = new JsonResult() { Data = new { Msg = "Out of frequency" } }; } }
What are the limitations of Filter?
Although it is rich, it can only use Action as a unit. Action calls other class libraries internally, and adding operations can not do it! This depends on IOC+AOP extensions.
This article only introduces the Filter filter (permission feature, action, Result, Exception) in. NET Framework MVC. Actually, in. NET Core MVC, ResourceFilter has been added, adding this feature, resource feature, and the three features of Action/Result/Exception have not changed. This will be described in detail later when it is recorded in. NET Core MVC.