• 17+个ASP.NET MVC扩展点【附源码】


    1、自定义一个HttpModule,并将其中的方法添加到HttpApplication相应的事件中!即:创建一个实现了IHttpmodule接口的类,并将配置WebConfig。
       在自定义的HttpModule中,可以将一个方法注册到HttpApplication的任意一个事件中,在之后执行HttpApplication一些列事件时,按照事件的顺序(事件又按照添加方法先后的顺序)执行注册在事件中的方法!

    namespace MvcStore.Models
    {
        public class ExcuteHttpRequestModule:IHttpModule
        {
            public void Init(HttpApplication context)
            {
                context.PostResolveRequestCache+=new EventHandler(this.context_ExecuteHttpRequst);
               
            }
            public void Dispose()
            {
               
            }
    
            public void context_ExecuteHttpRequst(object sender, EventArgs e)
            {
                HttpRequest httpRequest = HttpContext.Current.Request;
                Uri previousUri = httpRequest.UrlReferrer;
            }
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <!--
      有关如何配置 ASP.NET 应用程序的详细信息,请访问
      http://go.microsoft.com/fwlink/?LinkId=152368
      -->
    
    <configuration>
      <appSettings>
        <add key="webpages:Version" value="1.0.0.0"/>
        <add key="ClientValidationEnabled" value="true"/>
        <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
      </appSettings>
        
      <system.web>
        <!--自定义HttpModule,仅添加一下此段代码即可-->
        <httpModules>
          <add name="ExecuteHttpRequestModule" type="MvcStore.Models.ExcuteHttpRequestModule"/>
        </httpModules>
        
         ......等
    </configuration>
    

    例:创建一个HttpModule(实现IHttpModule接口),并将一个方法注册到HttpApplication的BeginRequest(HttpAppliaction的第一个事件)事件中,即:由于该方法注册在HttpApplication第一个事件中,所有无论是合法还是非法的请求地址,该方法都会被执行。

    利用HttpModule扩展知识,并通过NLog来完成写请求日志:源码下载

    补充:在ASP.NET MVC中,css和js的请求是合并到一起发送给服务端的!

    2、添加路由规则

     routes.MapRoute(
                    "Default", // 路由名称
                    "{controller}/{action}/{id}", // 带有参数的 URL
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
                );
    

    3、自定义MapRoute方法

      第一步中MapRoute方法其实就是RouteCollection的扩展方法,我们也可以定义一个。

    namespace System.Web.Mvc
    {
        
        public static class RouteCollectionExtensions
        {
            public static Route MapRoute(this RouteCollection routes, string name, string url)
            {
                return routes.MapRoute(name, url, null, null);
            }
    
            public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults)
            {
                return routes.MapRoute(name, url, defaults, null);
            }
        
            public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
            {
                return routes.MapRoute(name, url, defaults, constraints, null);
            }
            
            public static Route MapRoute(this RouteCollection routes, string name, string url, string[] namespaces)
            {
                return routes.MapRoute(name, url, null, null, namespaces);
            }
            
            public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
            {
                return routes.MapRoute(name, url, defaults, null, namespaces);
            }
            
            public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
            {
                if (routes == null)
                {
                    throw new ArgumentNullException("routes");
                }
                if (url == null)
                {
                    throw new ArgumentNullException("url");
                }
                Route route = new Route(url, new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(defaults),
                    Constraints = new RouteValueDictionary(constraints),
                    DataTokens = new RouteValueDictionary()
                };
                if (namespaces != null && namespaces.Length > 0)
                {
                    route.DataTokens["Namespaces"] = namespaces;
                }
                routes.Add(name, route);
                return route;
            }
        }
    }
    微软定义的MapRoute方法
    namespace MvcExtension.Models
    {
    
        public static class MyRouteCollectionExtensions
        {
            /// <summary>
            /// 自定义MapRoute方法
            /// </summary>
            /// <param name="routes"></param>
            /// <param name="routeHandler"></param>
            /// <param name="name"></param>
            /// <param name="url"></param>
            /// <param name="defaults"></param>
            /// <param name="constraints"></param>
            /// <param name="namespaces"></param>
            /// <returns></returns>
            public static Route MyMapRoute(this RouteCollection routes, IRouteHandler routeHandler, string name, string url,
                object defaults, object constraints, string[] namespaces)
            {
                if (routes == null)
                {
                    throw new ArgumentNullException("routes");
                }
                if (url == null)
                {
                    throw new ArgumentNullException("url");
                }
                if (routeHandler == null)
                {
                    throw new ArgumentNullException("routeHandler");
                }
                Route route = new Route(url, routeHandler)
                {
                    Defaults = new RouteValueDictionary(defaults),
                    Constraints = new RouteValueDictionary(constraints),
                    DataTokens = new RouteValueDictionary()
                };
                if (namespaces != null && namespaces.Length > 0)
                {
                    route.DataTokens["Namespaces"] = namespaces;
                }
                routes.Add(name, route);
                return route;
            }
    
            /// <summary>
            /// 自定义MapRoute方法
            /// </summary>
            /// <param name="routes"></param>
            /// <param name="name"></param>
            /// <param name="route"></param>
            /// <returns></returns>
            public static Route MyMapRoute(this RouteCollection routes, string name, Route route)
            {
                if (routes == null)
                {
                    throw new ArgumentNullException("routes");
                }
                if (route == null)
                {
                    throw new ArgumentNullException("route");
                }
                routes.Add(name, route);
                return route;
            }
        }
    }
    自定义的MapRoute方法

    注:在微软提供的MapRoute方法中可以看出,创建Route对象时,其构造函数的参数中有:new MvcRouteHandler。这个MvcRouteHandler用于之后创建HttpHandler对象,HttpHandler就是用来最后处理请求的!

    4、自定义MvcRouteHandler
      即:实现IRouteHandler接口,MVC默认使用MvcRouteHandler来创建HttpHandler对象,用来处理请求!

    namespace System.Web.Mvc
    {
        public class MvcRouteHandler : IRouteHandler
        {
            private IControllerFactory _controllerFactory;
            public MvcRouteHandler()
            {
            }
            public MvcRouteHandler(IControllerFactory controllerFactory)
            {
                this._controllerFactory = controllerFactory;
            }
            protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
            {
                requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
                return new MvcHandler(requestContext);
            }
            protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
            {
                string controllerName = (string)requestContext.RouteData.Values["controller"];
                IControllerFactory controllerFactory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
                return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
            }
            IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
            {
                return this.GetHttpHandler(requestContext);
            }
        }
    }
    微软定义的MvcRouteHandler

      定义:我们自定义MvcRouteHandler时只需实现IRouteHandler接口,具体实现参照微软定义的MvcRouteHandler类

        public class MyRouteHandler:IRouteHandler
        {
    		public MyRouteHandler()
    		{
    		}
    
    		protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
    		{
    			return new MvcHandler(requestContext);
    		}
    
    		IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
    		{
    			return this.GetHttpHandler(requestContext);
    		}
        }

      使用:结合2中创建的自定义的MapRoute方法,将自己的MvcRouteHandler对象添加到Route对象中!

    第2、3、4步骤示例:源码下载

    5、自定义MvcHandler

      对于微软的类MvcHandler其实就是一个HttpHandler(实现IHttpHandler接口),在MVC整个处理机制中,MvcHandler接收到请求并激活Controller、执行Action、View的呈现 等。MvcHandler是执行MvcRouteHandler的GetHttpHandler方法得到的!

        public class MyMvcHandler : IHttpHandler
        {
            public bool IsReusable
            {
                get { return false; }
            }
            public void ProcessRequest(HttpContext context)
            {
                HttpContext.Current.Response.Write("自定义的MvcHandler处理请求");
            }
        }

    在第2、3、4步骤的基础上,使用自定义MvcHandler处理请求:源码下载

    6、自定义ControllerFactory

      ControllerFactory用于Controller的激活,也就是创建Controller对象。对于MVC,这个ControllerFactiory是通过ControllerBuilder.Current.GetControllerFactory();得到,默认得到的ControllerFactory是DefaultControllerFactory对象!

    public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
    {
    
        internal ControllerBuilder ControllerBuilder
        {
            get
            {
                if (this._controllerBuilder == null)
                {
                    this._controllerBuilder = ControllerBuilder.Current;
                }
                return this._controllerBuilder;
            }
            set
            {
                this._controllerBuilder = value;
            }
        }
    
        protected virtual void ProcessRequest(HttpContext httpContext)
        {
            HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
            this.ProcessRequest(httpContext2);
        }
        
        protected internal virtual void ProcessRequest(HttpContextBase httpContext)
        {
            SecurityUtil.ProcessInApplicationTrust(delegate
            {
                IController controller;
                IControllerFactory controllerFactory;
                this.ProcessRequestInit(httpContext, out controller, out controllerFactory);
                try
                {
                    controller.Execute(this.RequestContext);
                }
                finally
                {
                    controllerFactory.ReleaseController(controller);
                }
            });
        }
        private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
        {
            if (ValidationUtility.IsValidationEnabled(HttpContext.Current) == true)
            {
                ValidationUtility.EnableDynamicValidation(HttpContext.Current);
            }
            this.AddVersionHeader(httpContext);
            this.RemoveOptionalRoutingParameters();
            string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
            //获取ControllerFactory
            factory = this.ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(this.RequestContext, requiredString);
            if (controller == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[]
                {
                    factory.GetType(),
                    requiredString
                }));
            }
        }
    }
    MvcHandler
    public class ControllerBuilder
    {
        private Func<IControllerFactory> _factoryThunk = () => null;
        //静态变量,自己创建本身对象
        private static ControllerBuilder _instance = new ControllerBuilder();
        private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        private IResolver<IControllerFactory> _serviceResolver;
    
        //Current
        public static ControllerBuilder Current
        {
            get
            {
                return ControllerBuilder._instance;
            }
        }
    
        public HashSet<string> DefaultNamespaces
        {
            get
            {
                return this._namespaces;
            }
        }
    
        public ControllerBuilder() : this(null)
        {
        }
    
        internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
        {
            IResolver<IControllerFactory> arg_6A_1 = serviceResolver;
            if (serviceResolver == null)
            {
                //默认情况下,_serviceResolver赋值为new DefaultControllerFactory
                arg_6A_1 = new SingleServiceResolver<IControllerFactory>(() => this._factoryThunk(), new DefaultControllerFactory
                {
                    ControllerBuilder = this
                }, "ControllerBuilder.GetControllerFactory");
            }
            this._serviceResolver = arg_6A_1;
        }
    
        public IControllerFactory GetControllerFactory()
        {
            //_serviceResolver.Current得到的是DefaultControllerFactory对象,在构造函数中赋值
            return this._serviceResolver.Current;
        }
    
        public void SetControllerFactory(IControllerFactory controllerFactory)
        {
            if (controllerFactory == null)
            {
                throw new ArgumentNullException("controllerFactory");
            }
            this._factoryThunk = (() => controllerFactory);
        }
    
        public void SetControllerFactory(Type controllerFactoryType)
        {
            if (controllerFactoryType == null)
            {
                throw new ArgumentNullException("controllerFactoryType");
            }
            if (!typeof(IControllerFactory).IsAssignableFrom(controllerFactoryType))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_MissingIControllerFactory, new object[]
                {
                    controllerFactoryType
                }), "controllerFactoryType");
            }
            this._factoryThunk = delegate
            {
                IControllerFactory result;
                try
                {
                    result = (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
                }
                catch (Exception innerException)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_ErrorCreatingControllerFactory, new object[]
                    {
                        controllerFactoryType
                    }), innerException);
                }
                return result;
            };
        }
    }
    ControllerBuilder

      上述两个类,MvcHandler中通过GetControllerFactory获取的就是通过ControllerBuilder的SetControllerFactory方法设置ControllerFactory(没有设置时,默认是DefaultControllerFactory)。这就是我们创建自定义ControllerFactory的入口。

        public class MyControllerFactory:IControllerFactory
        {
            public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
            {
               //根据controllerName和命名空间,通过反射创建Controller对象
                return null;
            }
    
            public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
            {
                //获取控制器的会话行为。
                return System.Web.SessionState.SessionStateBehavior.Default;//这里是随便列举的一个
            }
    
            public void ReleaseController(IController controller)
            {
                //释放Controller
            }
        }
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
            }
    
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.MapRoute(
                    "Default", // 路由名称
                    "{controller}/{action}/{id}", // 带有参数的 URL
                    new {controller = "Home", action = "Index", id = UrlParameter.Optional} // 参数默认值
                    );
    
            }
    
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
        
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
                //设置MyControllerFactory,让MyControllerFactory完成controller的激活
                ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
            }
        }
    

      上面就是简单的列举了执行流程,不再进行过多的介绍,因为在实际开发中,一般不会使用自定义一个ControllerFactory,因为其中包含的功能,我们自己来定义时可能考虑的不够全面,如果项目需求必须使用的话,要细看微软在DefaultControllerFactory中各种功能!!!既然不用自定义的ContollerFactory,那么就只能用DefaultControllerFactory了,DefaultControllerFactory中也有扩展点让我们利用,就是下面第7中介绍的!

    7、自定义ControllerActivator

      在6中我们讲到,DefaultControllerFactory用于创建Controller对象,而这个ControllerActivator实际上就是DefaultControllerFactory中负责创建Controller对象“组件”。默认情况下,使用的是微软提供的DefaultControllerActivator(DefaultControllerFactory的构造函数中设置)。

    private class DefaultControllerActivator : IControllerActivator
    {
        private Func<IDependencyResolver> _resolverThunk;
        public DefaultControllerActivator() : this(null)
        {
        }
        public DefaultControllerActivator(IDependencyResolver resolver)
        {
            if (resolver == null)
            {
                this._resolverThunk = (() => DependencyResolver.Current);
                return;
            }
            this._resolverThunk = (() => resolver);
        }
        public IController Create(RequestContext requestContext, Type controllerType)
        {
            IController result;
            try
            {
                result = (IController)(this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
            }
            catch (Exception innerException)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ErrorCreatingController, new object[]
                {
                    controllerType
                }), innerException);
            }
            return result;
        }
    }
    微软:DefaultControllerActivator

    自定义:
      定义:实现IControllerActivator接口
      使用:通过DefaultControllerFactory的构造函数将自定义ControllerActivator “注入”。
               在Global.asax中添加 ---> ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new MyControllerActivator()));

        public class MyControllerActivator:IControllerActivator
        {
            public IController Create(System.Web.Routing.RequestContext requestContext, Type controllerType)
            {
                return (IController)Activator.CreateInstance(controllerType);
            }
        }
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
        
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
    
                ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new MyControllerActivator()));
            }
    

      应用场景1:在Controller激活之前做一些操作
      应用场景2:通过Controller的构造函数实现在创建Controller对象时“注入”值!因为默认情况下,激活Controller的时候是执行的其无参数构造函数!

    应用场景2+依赖注入:源码下载

    8、自定义ActionInvoker

      ActionInvoker用于去执行被请求的Action方法,这过程中包含了 View的呈现 以及执行各种应用在Action上的特性(HttpMethod、Filter、DisplayName...等),由于功能忒多,所以不到不得已也不建议自己重写ActionInvoker。不过如果项目需要,可以继承微软默认使用的 ControllerActionInvoker,从而在已有功能的基础上添加自己的需要的功能!

     自定义:
      定义:实现IActionInvoker接口
      使用:在Controller的构造函数中设置自己的ActionInvoker

        public class MyActionInvoker:IActionInvoker
        {
            public bool InvokeAction(ControllerContext controllerContext, string actionName)
            {
                //根据action名称去找Action并执行,其中包括了 View的呈现 以及 应用在Action上的各种特性的执行
                //return false; //执行失败
                return true;    //执行成功
            }
        }
        public class HomeController : Controller
        {
            //微软的ControllerActivator激活Controller时,执行的就是无参数的构造函数!
            public HomeController()
            {
                base.ActionInvoker = new MyActionInvoker();
            }
    
            public ActionResult Index()
            {
                return Content("ddd");
            }
    
        }
    

    仅第8步骤示例:源码下载

    下面的9、10、11讲的是和特性相关的扩展,所以在介绍它们之前先来复习下MVC中使用的特性种类和处理流程:

      种类:

        ActionNameSelectorAttribute
            ActionNameAttribute
        ActionMethodSelectorAttribute
            AcceptVerbsAttribute
            HttpDeleteAttribute
            HttpGetAttribute
            HttpPostAttribute
            HttpPutAttribute
            NonActionAttribute
            HttpHeadAttribute
            HttpOptionsAttribute
            HttpPatchAttribute //灰色字体的是MVC4中新增的!
        FilterAttribute、IActionFilter或IAuthorizationFilter或IExceptionFilter或IResultFilter
            自定义类去实现相应接口

      处理流程:Contrller激活之后,要从Controller对象的方法中查找当前请求的Action,那么其流程为 ----> 先获取所有应用了ActionName特性并且ActionName特性设置的name=当前请求的Action名称(将符合条件的添加的List<MethodInfo>中),之后去获取所有没有应用ActionName特性的方法并且方法名=当前请求的Action名称,(再将符合条件的添加到之前创建的List<MethodInfo>尾部)再之后对符合名称条件的Action方法集合处理,判断应用在Action方法上的NonAction、AcceptVerbs、HttpGet等6个特性(MVC4有9个特性)是否和当前请求一致再再之后执行第三种过滤器,需要自己定义且实现接口,并应用在Action上,他们的执行顺序为:【IAuthorizationFilter】--->【IActionFilter】--->【Action方法内部代码】--->【IResultFilter】,如果上述4个过程中有异常抛出,则执行【IExceptionFilter】。个更多处理流程的介绍请猛击这里

    9、继承自ActionNameSelectorAttribute 的特性:ActionNameAttribute

      用于对Controller类中Action方法的重命名!当请求指定的 Controller/Action时,将用重命名后的名称去和请求的Action名称匹配。

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class ActionNameAttribute : ActionNameSelectorAttribute
    {
        public string Name
        {
            get;
            private set;
        }
    
        public ActionNameAttribute(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
            }
            this.Name = name;
        }
    
        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
        {
            return string.Equals(actionName, this.Name, StringComparison.OrdinalIgnoreCase);
        }
    }
    微软定义的ActionNameAttribute

    使用:

        public class HomeController : Controller
        {
            [ActionName("OtherName")]
            public ActionResult Index()
            {
                return Content("ddd");
            } 
        }
    

      如上设置ActionName后,当请求Home/Index就提示找不到无法找到资源,当请求Home/OtherName时,就会去执行这个Index方法!

    10、继承自ActionMethodSelectorAttribute的特性:AcceptVerbsAttribute...等

      该类特性中仅NonAction用于指示该方法不作为Action来使用,而其他的5个则都是用于判断Http请求的方式!

      HttpGet    只有客户端发送的是Get请求才能执行该Action
      HttpPost      只有客户端发送的是Post请求才能执行该Action ...Post请求
      HttpDelete     只有客户端发送的是Delete请求才能执行该Action
      HttpPut    只有客户端发送的是Put请求才能执行该Action
      AcceptVerbs  参数是一个枚举(Get、Post等),其功能和以上四个相同
    注:由于以上的特性类都应用了: [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)],所以这些特性只能应用在Action方法上并且每个只能使用一个。

    使用:仅列出HttpPost,其他使用方法相同,不再列举。

        public class HomeController : Controller
        {
            [HttpPost]
            public ActionResult Index()
            {
                return Content("ddd");
            } 
        }
    

      如上所示,只有客户端发送的是Post请求时,才能执行该Action。

    11、FilterAttribute、IActionFilter或IAuthorizationFilter或IExceptionFilter或IResultFilter

      该类过滤器执行的顺序为:【IAuthorizationFilter】--->【IActionFilter】--->【Action方法内部代码】--->【IResultFilter】,如果上述4个过程中有异常抛出,则执行【IExceptionFilter】。
      由于FilterAttribute类应用了 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)],所以该类特性可以应用在 类 或 方法 上且默认也只能使用一次,如果想要使用多个同样的特性,可以在自定义的特性上添加: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]即可。
      该类过滤器有 4 种添加
    方式:以特性应用在Action方法上、以特性应用在Controller类上、Global.asax文件中RegisterGlobalFilters方法中添加、在Controller中重写各个过滤器方法(因为Controller类都实现各个接口),区别是这4种方式的作用域不同!

       11-1、IAuthorizationFilter

        public class MyAuthroizeFilter : FilterAttribute, IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationContext filterContext)
            {   
                //如果此处为filterContext.Result赋一个ActionResult对象,则MVC不会再继续执行下面的过滤器和Action放,而是直接根据这个ActionResult对象进行View的呈现。
                //如果filterContext.Result为null,则MVC继续执行之后的各个过滤器和Action方法!
            }
        }
    

      微软定义的该类过滤器有:ChildActionOnlyAttribute、AuthorizeAttribute,可以参考这两个类来定义自己的IAuthorizationFilter过滤器。

    using System;
    namespace System.Web.Mvc
    {
        /// <summary>Represents an attribute that is used to indicate that an action method should be called only as a child action.</summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public sealed class ChildActionOnlyAttribute : FilterAttribute, IAuthorizationFilter
        {
            /// <summary>Called when authorization is required.</summary>
            /// <param name="filterContext">An object that encapsulates the information that is required in order to authorize access to the child action.</param>
            public void OnAuthorization(AuthorizationContext filterContext)
            {
                if (filterContext == null)
                {
                    throw new ArgumentNullException("filterContext");
                }
                if (!filterContext.IsChildAction)
                {
                    throw Error.ChildActionOnlyAttribute_MustBeInChildRequest(filterContext.ActionDescriptor);
                }
            }
        }
    }
    ChildActionOnlyAttribute
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Principal;
    using System.Web.Mvc.Resources;
    namespace System.Web.Mvc
    {
        /// <summary>Represents an attribute that is used to restrict access by callers to an action method.</summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
        public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
        {
            private readonly object _typeId = new object();
            private string _roles;
            private string[] _rolesSplit = new string[0];
            private string _users;
            private string[] _usersSplit = new string[0];
            /// <summary>Gets or sets the user roles.</summary>
            /// <returns>The user roles.</returns>
            public string Roles
            {
                get
                {
                    return this._roles ?? string.Empty;
                }
                set
                {
                    this._roles = value;
                    this._rolesSplit = AuthorizeAttribute.SplitString(value);
                }
            }
            /// <summary>Gets the unique identifier for this attribute.</summary>
            /// <returns>The unique identifier for this attribute.</returns>
            public override object TypeId
            {
                get
                {
                    return this._typeId;
                }
            }
            /// <summary>Gets or sets the authorized users.</summary>
            /// <returns>The authorized users.</returns>
            public string Users
            {
                get
                {
                    return this._users ?? string.Empty;
                }
                set
                {
                    this._users = value;
                    this._usersSplit = AuthorizeAttribute.SplitString(value);
                }
            }
            /// <summary>When overridden, provides an entry point for custom authorization checks.</summary>
            /// <returns>true if the user is authorized; otherwise, false.</returns>
            /// <param name="httpContext">The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request.</param>
            /// <exception cref="T:System.ArgumentNullException">The <paramref name="httpContext" /> parameter is null.</exception>
            protected virtual bool AuthorizeCore(HttpContextBase httpContext)
            {
                if (httpContext == null)
                {
                    throw new ArgumentNullException("httpContext");
                }
                IPrincipal user = httpContext.User;
                return user.Identity.IsAuthenticated && (this._usersSplit.Length <= 0 || this._usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) && (this._rolesSplit.Length <= 0 || this._rolesSplit.Any(new Func<string, bool>(user.IsInRole)));
            }
            private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
            {
                validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
            }
            /// <summary>Called when a process requests authorization.</summary>
            /// <param name="filterContext">The filter context, which encapsulates information for using <see cref="T:System.Web.Mvc.AuthorizeAttribute" />.</param>
            /// <exception cref="T:System.ArgumentNullException">The <paramref name="filterContext" /> parameter is null.</exception>
            public virtual void OnAuthorization(AuthorizationContext filterContext)
            {
                if (filterContext == null)
                {
                    throw new ArgumentNullException("filterContext");
                }
                if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
                {
                    throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
                }
                if (this.AuthorizeCore(filterContext.HttpContext))
                {
                    HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
                    cache.SetProxyMaxAge(new TimeSpan(0L));
                    cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), null);
                    return;
                }
                this.HandleUnauthorizedRequest(filterContext);
            }
            /// <summary>Processes HTTP requests that fail authorization.</summary>
            /// <param name="filterContext">Encapsulates the information for using <see cref="T:System.Web.Mvc.AuthorizeAttribute" />. The <paramref name="filterContext" /> object contains the controller, HTTP context, request context, action result, and route data.</param>
            protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
            /// <summary>Called when the caching module requests authorization.</summary>
            /// <returns>A reference to the validation status.</returns>
            /// <param name="httpContext">The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request.</param>
            /// <exception cref="T:System.ArgumentNullException">The <paramref name="httpContext" /> parameter is null.</exception>
            protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
            {
                if (httpContext == null)
                {
                    throw new ArgumentNullException("httpContext");
                }
                if (!this.AuthorizeCore(httpContext))
                {
                    return HttpValidationStatus.IgnoreThisRequest;
                }
                return HttpValidationStatus.Valid;
            }
            internal static string[] SplitString(string original)
            {
                if (string.IsNullOrEmpty(original))
                {
                    return new string[0];
                }
                IEnumerable<string> source = 
                    from piece in original.Split(new char[]
                    {
                        ','
                    })
                    let trimmed = piece.Trim()
                    where !string.IsNullOrEmpty(trimmed)
                    select trimmed;
                return source.ToArray<string>();
            }
        }
    }
    AuthorizeAttribute

    ==注意:如果在Controller上应用多个不同的IAuthorizationFilter过滤器,他们执行的顺序:由下向上。

      11-2、IActionFilter--->Action方法内部代码--->IResultFilter

      IActionFilter有两个方法OnActionExecuting(在执行操作方法之前调用)、OnActionExecuted(在执行操作方法后调用)。IResultFilter也有两个方法OnResultExecuting(在操作结果执行之前调用)、OnResultExecuted(在操作结果执行后调用),由于这里说的【在执行操作方法后调用】和【在操作结果执行之前调用】容易造成混淆,这里我们就来确定的说明一下其执行流程为:OnActionExecuting--->OnActionExecuted--->Action方法内的代码--->OnResultExecuting--->OnResultExecuted

        public class MyActionFilter :FilterAttribute, IActionFilter
        {
            public void OnActionExecuted(ActionExecutedContext filterContext)
            {
                //如果此处为filterContext.Result赋一个ActionResult对象,则MVC不会再继续执行下面的过滤器,而是直接根据这个ActionResult对象进行View的呈现。
                //如果filterContext.Result为null,则MVC按照 Action方法内返回的ActionResult进行View的呈现
            }
    
            public void OnActionExecuting(ActionExecutingContext filterContext)
            {
                //如果此处为filterContext.Result赋一个ActionResult对象,则MVC不会再继续执行下面的过滤器和Action方法,而是直接根据这个ActionResult对象进行View的呈现。
                //如果filterContext.Result为null,则MVC继续执行之后的各个过滤器和Action方法!
            }
        }
    
        public class MyResultFilter : FilterAttribute,IResultFilter
        {
    
            public void OnResultExecuted(ResultExecutedContext filterContext)
            {
                //如果此处为filterContext.Result赋一个ActionResult对象,MVC会直接根据这个ActionResult对象进行View的呈现。
                //如果filterContext.Result为null,则MVC按照 Action方法内返回的ActionResult进行View的呈现
            }
    
            public void OnResultExecuting(ResultExecutingContext filterContext)
            {
                //如果此处为filterContext.Result赋一个ActionResult对象,MVC会直接根据这个ActionResult对象进行View的呈现。
                //如果filterContext.Result为null,则MVC按照 Action方法内返回的ActionResult进行View的呈现
            }
        }
    

      11-3、IExceptionFilter

      Action方法上应用该特性后,如果执行:IAuthorizationFilter过滤器、IActionFilter过滤器、Action方法内的代码、IResultFilter过滤器,抛出了异常,则会执行该方法!(只要出现有异常,则不会再继续往下执行后面的过滤器)

        public class MyExceptionFilter : FilterAttribute, IExceptionFilter
        {
            public void OnException(ExceptionContext filterContext)
            {
                //如果filterContext.ExceptionHandled = false(默认),则直接抛出异常。(filterContext.ExceptionHandled表示是否已经处理异常)
                //否则,为filterContext.Result赋一个ActionResult,使用这个ActionResult执行View的呈现!
            }
        }
    

    12、自定义ActionResult

       自定义一个ActionResult,只需要继承抽象类ActionResult,并实现其抽象方法ExecuteResult即可!微软中已经定义很多ActionResult(EmptyResult、ContentResult、JsonResult、ViewResult等)。

        public class MyActionResult : ActionResult
        {
            public override void ExecuteResult(ControllerContext context)
            {
                HttpContext.Current.Response.Write("自定义的ActionResult");
            }
        }
    

    使用时,只需要创建一个MyActionResult对象并让Action方法将其返回,或者在第11中任何一个过滤器中创建一个MyActionResult对象并赋值给filterContext.Result。下面是两个使用MyActionResult的例子:

        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return new MyActionResult();
            } 
        }
        public class HomeController : Controller
        {
            [MyAuthroizeFilter]
            public ActionResult Index()
            {
                return Content("123");
            } 
        }
    
        public class MyAuthroizeFilter : FilterAttribute, IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationContext filterContext)
            {
                filterContext.Result = new MyActionResult();
            }
        }
    

    定义一个生成验证码的VerifyCodeResult示例:源码下载

    13、自定义HtmlHelper

      在 .cshtml 文件中 使用的 @Html.TextBox(...)等,他们都是HtmlHelper类的扩展方法(定义在System.Web.Mvc.Html.InputExtensions中),更多关于@Html.xxx()方法的详细介绍请:猛击这里

        public static class MyHtmlHelperExtensions
        {
            public static MvcHtmlString MyControl(this HtmlHelper html, string str)
            {
                return MvcHtmlString.Create("自定义Html标签");
            }
        }

    使用HtmlHelper扩展开发一个【分页功能】:源码下载

    14、自定义ModelBinder

    15、自定义ValueProvider

      在学习 第14、15 扩展点之前,先来思考下! 在我们定义的Action方法中,他们的参数值是如何得到的呢?
      答:通过这第14、15个扩展点会让你对参数值的得到有个清楚的认识!在我的《白话学习MVC系列》的模型绑定一篇中已经做了详细的介绍!【猛击这里】

    下面的第16、17扩展点是【View呈现】步骤中,寻找【视图页】过程中用到的,详细介绍:猛击这里

    16、指定DefaultDisplayMode
    模拟需求:对Phone端用户的某个Action请求,返回电脑版网页。

    public ActionResult Index()
    {
        this.ControllerContext.DisplayMode = DisplayModeProvider.Instance.Modes[1];
        DisplayModeProvider.Instance.RequireConsistentDisplayMode = true;
        return View();
    }
    

      根据上述设置,即使是Phone端的请求并且还存在Index.Mobile.cshtml文件,也会去执行Index.cshtml,即:实现Phone用户访问电脑版网页。

    17、自定义DefaultDisplayMode
    模拟需求:为Android 2.3用户设置特定的页面
    先创建一个类似于Index.Android23.cshtml 的页面,然后在Global.asax中做如下设置即可:

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
     
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
     
            DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("Android23")
            {
                ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf
                ("Android 2.3", StringComparison.OrdinalIgnoreCase) >= 0)
            });
        }
    }
    

      

    如果还有没提到的扩展点,请指出!!!

  • 相关阅读:
    P1642 规划 [01分数规划]
    01分数规划学习笔记
    P1527 [国家集训队]矩阵乘法 [整体二分]
    P3292 [SCOI2016]幸运数字 [线性基+倍增]
    java中遍历集合的三种方式
    20190706中兴提前批专业面面经
    《java入门如此简单》——语句,函数和数组
    java中数组常见的操作
    2019 波克城市ava面试笔试题 (含面试题解析)
    2019 华云数据java面试笔试题 (含面试题解析)
  • 原文地址:https://www.cnblogs.com/wupeiqi/p/3570445.html
Copyright © 2020-2023  润新知