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)
});
}
}
如果還有沒提到的擴充點,請指出!!!
作者:武沛齊
出處:http://www.cnblogs.com/wupeiqi/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。