zoukankan      html  css  js  c++  java
  • 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)
            });
        }
    }
    

      

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

  • 相关阅读:
    共享纸巾更换主板代码分析 共享纸巾主板更换后的对接代码
    Python Django Ajax 传递列表数据
    Python Django migrate 报错解决办法
    Python 创建字典的多种方式
    Python 两个list合并成一个字典
    Python 正则 re.sub替换
    python Django Ajax基础
    Python Django 获取表单数据的三种方式
    python Django html 模板循环条件
    Python Django ORM 字段类型、参数、外键操作
  • 原文地址:https://www.cnblogs.com/wupeiqi/p/3570445.html
Copyright © 2011-2022 走看看