ASP.NET MVC实践系列9-filter原理与实践

filter实际上是一个特性(attribute),它提供了一种向controller 或 action中添加某些任务的方法,当controller 或 action被调用时,会触发filter中定义的相应方法。filter应该算AOP的一种实现方式,关于AOP的内容大家可以参考张逸的文章http://www.cnblogs.com/wayfarer/articles/241024.html,图文并茂对AOP讲解的十分清楚。所以我们就可以在某种程度上利用filter来分解横向和纵向的应用,比方说日志,权限,缓存,防盗链等等应用。

一、我们先来看看ASP.NET MVC 框架提供的几种默认filter类型:
1、Authorize:

准备工作:进入C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727文件夹,双击aspnet_regsql.exe选择好相应的数据库,创建membership,AuthorizeAttribute使用membership来进行权限验证的,所以我们需要先在membership中准备一个用户lfm,一个角色Admin,我们使用studio的项目-》ASP.NET配置创建即可。

  [Authorize(Roles = " Admin " )]
        
public  ActionResult Index()
        {
            ViewData[
" Message " =   " Welcome to ASP.NET MVC! " ;

            
return  View();
        }

如果lfm不属于Admin角色时Index页是不能访问的

2、OutputCache:

 [OutputCache(Duration = 60 , VaryByParam = " none " )]
        
public  ActionResult About()
        {
            
return  View();
        }

然后我们修改About加入:

 <%=DateTime.Now.ToString() %>

我们会发现在一分钟内我们刷新About页面其输出并不改变。这个和webform中的页面缓存机制非常相似。

这里我们也可以统一的配置时间和条件

ContractedBlock.gif ExpandedBlockStart.gif 配置文件
    <system.web>
      
<caching>
        
<outputCacheSettings>
          
<outputCacheProfiles>
            
<add name="MyProfile" duration=60” varyByParam=”none” />
          
</outputCacheProfiles>
        
</outputCacheSettings>
      
</caching>
    
</system.web>

Controler中输入

  [OutputCache(CacheProfile = " MyProfile " )]
        
public  ActionResult About()
        {
            
return  View();
        }

3、Exception

ContractedBlock.gif ExpandedBlockStart.gif Exception
       [HandleError(ExceptionType = typeof(ArgumentException), View = "Error")]
        
public ActionResult GetProduct(string name)
        {
            
if (name == null)
            {
                
throw new ArgumentNullException("名字为空");
            }
            
return View();
        }

标明HandleError属性后的Action,当内部出现异常时会根据异常类型跳转到相应的View,这里需要注意的是上面的源码在开发期无法看到效果,必须部署到iis上才能看到效果。实际上这个简单处理在项目中用处不大,一般我们都会写自己的异常处理方式,自定义异常处理我们一会再自定义filter中讲解。

二、自定义filter实例:

我们先来看一下跟filter相关的类结构:

一般情况下我们自定义的filter都是继承FilterAttribute类然后再扩展相应的接口的,下面我们举几个例子:

1、自定义异常处理

ContractedBlock.gif ExpandedBlockStart.gif 自定义异常处理
 1 public class ExceptionFilter : FilterAttribute,IExceptionFilter
 2     {
 3         void IExceptionFilter.OnException(ExceptionContext filterContext)
 4         {
 5             filterContext.Controller.ViewData["ErrorMessage"= filterContext.Exception.Message;
 6             filterContext.Result = new ViewResult()
 7             {
 8                 ViewName = "Error",
 9                 ViewData = filterContext.Controller.ViewData,
10             };
11             filterContext.ExceptionHandled = true;
12         }

使用

ContractedBlock.gif ExpandedBlockStart.gif Controller
  [ExceptionFilter]
        
public ActionResult GetView(string name)
        {
            
if (name == null)
            {
                
throw new ArgumentNullException("名字为空");
            }
            
return View();
        }

浏览器中输入:http://localhost:3983/Home/GetView

这样我们就可以根据自己的项目情况来处理异常了。

2、监控Action运行时间的Timer

ContractedBlock.gif ExpandedBlockStart.gif TimerAttribute
 1 using System.Diagnostics;
 2 using System.Web.Mvc;
 3 public class TimerAttribute : ActionFilterAttribute
 4 {
 5     public TimerAttribute()
 6     {
 7         //By default, we should be the last filter to run
 8         //so we run just before and after the action method.
 9         this.Order = int.MaxValue;
10     }
11     public override void OnActionExecuting(ActionExecutingContext filterContext)
12     {
13         var controller = filterContext.Controller;
14         if (controller != null)
15         {
16             var stopwatch = new Stopwatch();
17             controller.ViewData["__StopWatch"= stopwatch;
18             stopwatch.Start();
19         }
20     }
21     public override void OnActionExecuted(ActionExecutedContext filterContext)
22     {
23         var controller = filterContext.Controller;
24         if (controller != null)
25         {
26             var stopwatch = (Stopwatch)controller.ViewData["__StopWatch"];
27             stopwatch.Stop();
28             controller.ViewData["__Duration"= stopwatch.Elapsed.TotalMilliseconds;
29         }
30     }
31 }

使用

 [Timer]
        
public  ActionResult TestTimer()
        {
            Thread.Sleep(
100 );
            
return  View();
        }

页面显示:

<%=ViewData["__Duration"]%>

三、filter相关接口方法的执行顺序:

根据上面的结构图我们知道跟filter相关的总共有四个接口,六个方法,这些方法如果在同一个类中实现时是有个优先级顺序的

IAuthorizationFilter>IActionFilter>IResultFilter>IExceptionFilter
接下来我们写个程序来验证这个顺序:

ContractedBlock.gif ExpandedBlockStart.gif TestOrder属性类
 1 using System.Web.Mvc;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 namespace FilterDemo.Controllers
 5 {
 6     public class TestOrderAttribute : FilterAttribute, IResultFilter, IActionFilter, IAuthorizationFilter, IExceptionFilter
 7     {
 8         #region IResultFilter 成员
 9 
10         public void OnResultExecuted(ResultExecutedContext filterContext)
11         {
12             Write( "OnResultExecuted");
13             
14         }
15 
16         private static void Write(string methodName)
17         {
18             StreamWriter sw = new StreamWriter("c:\\test.txt",true);
19             sw.WriteLine(methodName);
20             sw.Close();
21         }
22 
23         public void OnResultExecuting(ResultExecutingContext filterContext)
24         {
25             Write( "OnResultExecuting");
26         }
27 
28         #endregion
29 
30         #region IActionFilter 成员
31 
32         public void OnActionExecuted(ActionExecutedContext filterContext)
33         {
34             Write( "OnActionExecuted");
35         }
36 
37         public void OnActionExecuting(ActionExecutingContext filterContext)
38         {
39             Write( "OnActionExecuting");
40         }
41 
42         #endregion
43 
44         #region IAuthorizationFilter 成员
45 
46         public void OnAuthorization(AuthorizationContext filterContext)
47         {
48             Write("OnAuthorization");
49         }
50 
51         #endregion
52 
53         #region IExceptionFilter 成员
54 
55         public void OnException(ExceptionContext filterContext)
56         {
57             Write("OnException");
58             filterContext.ExceptionHandled = true;
59         }
60 
61         #endregion
62     }
63 
64 }

使用

[TestOrder]
        
public  ActionResult TestFilterOrder()
        {
           
//  throw new Exception("lfm");
             return  View();
        }

前端

<%throw new Exception("异常出现"); %>

这时候我们打开c:\test.txt得到的结果为:

OnAuthorization
OnActionExecuting
OnActionExecuted
OnResultExecuting
OnResultExecuted
OnException

四、参考

《Professional ASP.NET MVC 1.0》

http://www.cnblogs.com/leoo2sk/archive/2008/11/05/1326655.html

http://www.cnblogs.com/wayfarer/articles/241024.html

http://www.cnblogs.com/chsword/archive/2009/03/12/zd_mvc6.html

五、源码

 

我的ASP.NET MVC实践系列

ASP.NET MVC实践系列1-UrlRouting

ASP.NET MVC实践系列2-简单应用

ASP.NET MVC实践系列3-服务器端数据验证

ASP.NET MVC实践系列4-Ajax应用

ASP.NET MVC实践系列5-结合jQuery

ASP.NET MVC实践系列6-Grid实现(上)

ASP.NET MVC实践系列7-Grid实现(下-利用Contrib实现)

ASP.NET MVC实践系列8-对查询后分页处理的解决方案

其他:

在ASP.NET MVC中对表进行通用的增删改

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值