一、自定義一個HttpModule,並將其中的方法添加到HttpApplication相應的事件中!即:建立一個實現了IHttpmodule接口的類,並將配置WebConfig。
在自定義的HttpModule中,能夠將一個方法註冊到HttpApplication的任意一個事件中,在以後執行HttpApplication一些列事件時,按照事件的順序(事件又按照添加方法前後的順序)執行註冊在事件中的方法!css
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第一個事件中,全部不管是合法仍是非法的請求地址,該方法都會被執行。html
利用HttpModule擴展知識,並經過NLog來完成寫請求日誌:源碼下載web
補充:在ASP.NET MVC中,css和js的請求是合併到一塊兒發送給服務端的!app
二、添加路由規則ide
routes.MapRoute( "Default", // 路由名稱 "{controller}/{action}/{id}", // 帶有參數的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數默認值 );
三、自定義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; } } }
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方法中能夠看出,建立Route對象時,其構造函數的參數中有:new MvcRouteHandler。這個MvcRouteHandler用於以後建立HttpHandler對象,HttpHandler就是用來最後處理請求的!字體
四、自定義MvcRouteHandler
即:實現IRouteHandler接口,MVC默認使用MvcRouteHandler來建立HttpHandler對象,用來處理請求!ui
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時只需實現IRouteHandler接口,具體實現參照微軟定義的MvcRouteHandler類this
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對象中!
第二、三、4步驟示例:源碼下載
五、自定義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處理請求"); } }
在第二、三、4步驟的基礎上,使用自定義MvcHandler處理請求:源碼下載
六、自定義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 })); } } }
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; }; } }
上述兩個類,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中介紹的!
七、自定義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; } }
自定義:
定義:實現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+依賴注入:源碼下載
八、自定義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步驟示例:源碼下載
下面的九、十、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】。個更多處理流程的介紹請猛擊這裏!
九、繼承自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); } }
使用:
public class HomeController : Controller { [ActionName("OtherName")] public ActionResult Index() { return Content("ddd"); } }
如上設置ActionName後,當請求Home/Index就提示找不到沒法找到資源,當請求Home/OtherName時,就會去執行這個Index方法!
十、繼承自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。
十一、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-一、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); } } } }
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>(); } } }
==注意:若是在Controller上應用多個不一樣的IAuthorizationFilter過濾器,他們執行的順序:由下向上。
11-二、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-三、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的呈現! } }
十二、自定義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示例:源碼下載
1三、自定義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擴展開發一個【分頁功能】:源碼下載
1四、自定義ModelBinder
1五、自定義ValueProvider
在學習 第1四、15 擴展點以前,先來思考下! 在咱們定義的Action方法中,他們的參數值是如何獲得的呢?
答:經過這第1四、15個擴展點會讓你對參數值的獲得有個清楚的認識!在個人《白話學習MVC系列》的模型綁定一篇中已經作了詳細的介紹!【猛擊這裏】
下面的第1六、17擴展點是【View呈現】步驟中,尋找【視圖頁】過程當中用到的,詳細介紹:猛擊這裏
1六、指定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用戶訪問電腦版網頁。
1七、自定義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) }); } }
若是還有沒提到的擴展點,請指出!!!