您的位置:首页 > 编程语言 > ASP

Asp.net MVC 示例项目"Suteki.Shop"分析之---Filter

2009-05-14 08:06 706 查看
在Suteki.Shop中对于Filter的使用上提供了两种方式,一种是从FilterAttribute

(抽象类属性)以及接口 IActionFilter和 IResultFilter中继承并实现。另一种是我们经

常提到的从ActionFilterAttribute 上继承方式来实现自己的ActionFilter。首先看一下

第一种,同时它也是该项目中被Action广泛使用的方式, 下面是类图:




当然图中最核心的当属FilterUsingAttribute,它同时继承了 FilterAttribute类和

IAuthorizationFilter, IActionFilter, IResultFilter这三个接口,所以其所实现的功能

与MVC中所定义的ActionFilterAttribute如出一辙。同时,下面是其核心代码:

public class FilterUsingAttribute : FilterAttribute, IAuthorizationFilter, IActionFilter, IResultFilter

{

private readonly Type filterType;

private object instantiatedFilter;

public FilterUsingAttribute(Type filterType)

{

if(!IsFilterType(filterType))

{

throw new InvalidOperationException("Type '{0}' is not valid within the FilterUsing

attribute as it is not a filter type.".With(filterType.Name));

}

this.filterType = filterType;

}

private bool IsFilterType(Type type)

{

return typeof(IAuthorizationFilter).IsAssignableFrom(type)

|| typeof(IActionFilter).IsAssignableFrom(type)

|| typeof(IResultFilter).IsAssignableFrom(type);

}

public Type FilterType

{

get { return filterType; }

}

private T GetFilter<T>() where T : class

{

if(instantiatedFilter == null)

{

instantiatedFilter = ServiceLocator.Current.GetInstance(filterType);

}

return instantiatedFilter as T;

}

private void ExecuteFilterWhenItIs<TFilter>(Action<TFilter> action) where TFilter :class

{

var filter = GetFilter<TFilter>();

if(filter != null)

{

action(filter);

}

}

public void OnAuthorization(AuthorizationContext filterContext)

{

ExecuteFilterWhenItIs<IAuthorizationFilter>(f => f.OnAuthorization(filterContext));

}

public void OnActionExecuting(ActionExecutingContext filterContext)

{

ExecuteFilterWhenItIs<IActionFilter>(f => f.OnActionExecuting(filterContext));

}



public void OnActionExecuted(ActionExecutedContext filterContext)

{

ExecuteFilterWhenItIs<IActionFilter>(f => f.OnActionExecuted(filterContext));

}

public void OnResultExecuting(ResultExecutingContext filterContext)

{

ExecuteFilterWhenItIs<IResultFilter>(f => f.OnResultExecuting(filterContext));

}

public void OnResultExecuted(ResultExecutedContext filterContext)

{

ExecuteFilterWhenItIs<IResultFilter>(f => f.OnResultExecuted(filterContext));

}

}


在上面的OnAction..和OnResult..事件中,都调用了ExecuteFilterWhenItIs这个泛型方法,

而该方法的作用是对泛型约束中使用到的相应IActionFilter进行操作,而获取相应的Filter实例

的工作就交给了GetFilter<T>()方法,因为该方法使用IOC方式将filterType以服务组件的方式进

行创建,所以我们会看到在ContainerBuilder(Suteki.Shop/ContainerBuilder.cs)中有如下代

码,注意最后一行:

container.Register(

Component.For<IUnitOfWorkManager>().ImplementedBy<LinqToSqlUnitOfWorkManager>().LifeStyle.Transient,

Component.For<IFormsAuthentication>().ImplementedBy<FormsAuthenticationWrapper>(),

Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),







看来其最终会使用Castle框架所提供的IOC功能。



其实理解上面代码并不难,就是Suteki.Shop以自己实现的FilterUsingAttribute代替了MVC

自己的 ActionFilterAttribute, (当然它做的并不彻底,大家会在接下来的内容中看到)。当然有

了FilterUsingAttribute之后,Suteki.Shop并没有直接就去在Action中直接使用它,而是以它派

生出了几个Filter属性:

UnitOfWorkAttribute:项目中大部分Action使用

AuthenticateAttribute:用户信息认证

LoadUsingAttribute



其中UnitOfWorkAttribute和AuthenticateAttribute被用的最多,下面就分别加以介绍说明。



首先是UnitOfWorkAttribute,其构造方法声明中将UnitOfWorkFilter作为其基类方法的构

造类型,如下:

public class UnitOfWorkAttribute : FilterUsingAttribute

{

public UnitOfWorkAttribute() : base(typeof (UnitOfWorkFilter))

{

}

}

public class UnitOfWorkFilter : IActionFilter

{

private readonly IDataContextProvider provider;

public UnitOfWorkFilter(IDataContextProvider provider)

{

this.provider = provider;

}

public void OnActionExecuting(ActionExecutingContext filterContext)

{

}

public void OnActionExecuted(ActionExecutedContext filterContext)

{

var context = provider.DataContext;

if (filterContext.Controller.ViewData.ModelState.IsValid)

{

context.SubmitChanges();

}

}

}


其要实现的功能主要是对用户所做的数据操作进行判断,如果没有发生异常:

ModelState.IsValid为True时,则提交所做的修改到数据库中。

接下来再看一个AuthenticateAttribute,前面说过,其所实现的功能就是对当前

用户身份进行验证,其核心代码如下,因为内容比较简单,大家一看便知。

public class AuthenticateAttribute : FilterUsingAttribute

{

public AuthenticateAttribute() : base(typeof(AuthenticateFilter))

{

Order = 0;

}

}

public class AuthenticateFilter : IAuthorizationFilter

{

private IRepository<User> userRepository;

private IFormsAuthentication formsAuth;

public AuthenticateFilter(IRepository<User> userRepository, IFormsAuthentication formsAuth)

{

this.userRepository = userRepository;

this.formsAuth = formsAuth;

}

public void OnAuthorization(AuthorizationContext filterContext)

{

var context = filterContext.HttpContext;

if(context.User != null && context.User.Identity.IsAuthenticated)

{

var email = context.User.Identity.Name;

var user = userRepository.GetAll().WhereEmailIs(email);

if (user == null)

{

formsAuth.SignOut();

}

else

{

AuthenticateAs(context, user);

return;

}

}

AuthenticateAs(context, User.Guest);

}

private void AuthenticateAs(HttpContextBase context, User user)

{

Thread.CurrentPrincipal = context.User = user;

}

}

当然在本文开篇说过,Suteki.Shop也使用了我们经常用到的方式,即从ActionFilterAttribute

继承实现自己的ActionFilter,比如说CopyMessageFromTempDataToViewData(Suteki.Shop

/Filters/CopyMessageFromTempDataToViewData.cs),从字面可以看出,其要实现的功能就

是把临时数据复制到ViewData中,以便于前台视图显示,下面是其类图:




其实现代码如下:

public class CopyMessageFromTempDataToViewData : ActionFilterAttribute

{

public override void OnActionExecuted(ActionExecutedContext filterContext)

{

var result = filterContext.Result as ViewResult;

if(result != null && filterContext.Controller.TempData.ContainsKey("message"))

{

var model = result.ViewData.Model as ShopViewData;

if(model != null && string.IsNullOrEmpty(model.Message))

{

model.Message = filterContext.Controller.TempData["message"] as string;

}

}

}

}


其实看到这里,我感觉Suteki.Shop对于ActionFilter的使用还有待商榷,必定 MVC中的 Filter

是一种耗时的操作,对于程序的运行速度和执行效率来说都是一个考验。这其实也能部分解释为什么我

在本地运行Suteki.Shop时速度会比较慢。

这里不妨开句玩笑,Suteki.Shop开发者似乎得到ActionFilter强迫症,因为我感觉一个项目中一

个Action绑定的Filter最好别超过2个,否则必然会影响程序运行效率,尽管Suteki.Shop基本上控制

在了2个左右,但其还是运行速度偏慢。当然这里我并没有做到具体的测试,只是部分猜测,不过有兴

趣的朋友不妨测试一下,看看结果如何,相信会见分晓。

好了,今天的内容就先到这里了。



原文链接:http://www.cnblogs.com/daizhj/archive/2009/05/14/1453885.html

作者: daizhj,代震军,LaoD

Tags: mvc,Suteki.Shop

网址: http://daizhj.cnblogs.com/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: