我正在使用MVC4
来构建ASP.NET
应用程序。我在我的业务逻辑中使用ActionFilterAttribute
和AuthorizeAttribute
。以下是示例代码
控制器类
[SessionExpire]
[AuthorizeSubscription]
public class StoreController : Controller
{
public ActionResult StoreDetail()
{
// My logic goes here
}
[AuthorizeProductEdit]
[HttpGet]
public ActionResult EditProduct()
{
// My logic goes here
}
如果我们查看代码,我首先使用继承SessionExpire
类的ActionFilterAttribute
属性,检查session
是否对当前请求有效并在那里进行重定向。接下来,我正在检查继承AuthorizeSubscription
类的AuthorizeAttribute
属性。它还根据写在那里的逻辑进行一些重定向。
在EditProduct
行动中,我使用了另一个AuthorizeAttribute
。
如果我在没有制作任何StoreDetail
的情况下点击了session
Action的url,它会将我重定向到所需的页面。
但是,如果我为EditProduct
动作击中网址,它会引发我Object Reference error
。在调试期间它首先进入AuthorizeProdcutEdit
的代码,但找不到Session
Null失败。
为什么它不首先执行SessionExpire
代码并从那里退出如果找到Session
Null?
对于MSDN:
过滤器按以下顺序运行:
- 授权过滤器
- 动作过滤器
- 响应过滤器
- 异常过滤器
您的SessionExpire
属性在AuthorizeSubscription
属性之后触发的原因是因为MVC始终首先触发授权过滤器。
所以要解决这个问题,你需要你的SessionExpire
来实现IAuthorizationFilter
(并且可能继承Attribute
)。
此外,您将需要set the order of your attributes,因为.NET框架不保证它们将被处理的顺序。
[SessionExpire(Order=1)]
[AuthorizeSubscription(Order=2)]
public class StoreController : Controller
{
// Remaining implementation...
请注意,最好的方法是separate your filters from your attributes,它们都允许它们对DI友好,并且还允许您通过以特定顺序全局注册过滤器来明确设置顺序。
根据MSDN,过滤属性的顺序首先由其类型(例如授权过滤器,动作过滤器等)确定,然后由其范围(例如控制器范围,操作范围)确定。
您的SessionExpire
属性具有Action类型,范围Controller。您的AuthorizeProductEdit
属性具有类型Authorization,scope Action。
这就是为什么你的AuthorizeProductEdit
属性首先出现的原因。
来自documentation(我的重点)
ASP.NET MVC框架支持四种不同类型的过滤器:
授权过滤器 - 实现IAuthorizationFilter属性。
操作过滤器 - 实现IActionFilter属性。
结果过滤器 - 实现IResultFilter属性。
异常过滤器 - 实现IExceptionFilter属性。
过滤器按上面列出的顺序执行。例如,在操作过滤器和异常过滤器总是在每种其他类型的过滤器之后执行之前,始终执行授权过滤器。