1、自定义一个HttpModule,并将其中的方法添加到HttpApplication相应的事件中!即:创建一个实现了IHttpmodule接口的类,并将配置WebConfig。
在自定义的HttpModule中,可以将一个方法注册到HttpApplication的任意一个事件中,在之后执行HttpApplication一些列事件时,按照事件的顺序(事件又按照添加方法先后的顺序)执行注册在事件中的方法!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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;
}
}
} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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、添加路由规则
1
2
3
4
5
|
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; } } }
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就是用来最后处理请求的!
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时只需实现IRouteHandler接口,具体实现参照微软定义的MvcRouteHandler类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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方法得到的!
1
2
3
4
5
6
7
8
9
10
11
|
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 })); } } }
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的入口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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
}
} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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; } }
自定义:
定义:实现IControllerActivator接口
使用:通过DefaultControllerFactory的构造函数将自定义ControllerActivator
“注入”。
在Global.asax中添加
---> ControllerBuilder.Current.SetControllerFactory(new
DefaultControllerFactory(new MyControllerActivator()));
1
2
3
4
5
6
7
|
public
class MyControllerActivator:IControllerActivator
{ public
IController Create(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return
(IController)Activator.CreateInstance(controllerType);
}
} |
1
2
3
4
5
6
7
8
9
|
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
1
2
3
4
5
6
7
8
9
|
public
class MyActionInvoker:IActionInvoker
{ public
bool InvokeAction(ControllerContext controllerContext, string
actionName)
{
//根据action名称去找Action并执行,其中包括了 View的呈现 以及 应用在Action上的各种特性的执行
//return false; //执行失败
return
true ; //执行成功
}
} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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); } }
使用:
1
2
3
4
5
6
7
8
|
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,其他使用方法相同,不再列举。
1
2
3
4
5
6
7
8
|
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
1
2
3
4
5
6
7
8
|
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>(); } } }
11-2、IActionFilter--->Action方法内部代码--->IResultFilter
IActionFilter有两个方法OnActionExecuting(在执行操作方法之前调用)、OnActionExecuted(在执行操作方法后调用)。IResultFilter也有两个方法OnResultExecuting(在操作结果执行之前调用)、OnResultExecuted(在操作结果执行后调用),由于这里说的【在执行操作方法后调用】和【在操作结果执行之前调用】容易造成混淆,这里我们就来确定的说明一下其执行流程为:OnActionExecuting--->OnActionExecuted--->Action方法内的代码--->OnResultExecuting--->OnResultExecuted
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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过滤器,抛出了异常,则会执行该方法!(只要出现有异常,则不会再继续往下执行后面的过滤器)
1
2
3
4
5
6
7
8
|
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等)。
1
2
3
4
5
6
7
|
public
class MyActionResult : ActionResult
{ public
override void ExecuteResult(ControllerContext context)
{
HttpContext.Current.Response.Write( "自定义的ActionResult" );
}
} |
使用时,只需要创建一个MyActionResult对象并让Action方法将其返回,或者在第11中任何一个过滤器中创建一个MyActionResult对象并赋值给filterContext.Result。下面是两个使用MyActionResult的例子:
1
2
3
4
5
6
7
|
public
class HomeController : Controller
{ public
ActionResult Index()
{
return
new MyActionResult();
}
} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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()方法的详细介绍请:猛击这里
1
2
3
4
5
6
7
|
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系列》的模型绑定一篇中已经做了详细的介绍!【猛击这里】