zoukankan      html  css  js  c++  java
  • Asp.net MVC 示例项目"Suteki.Shop"分析之Filter

          在Suteki.Shop中对于Filter的使用上提供了两种方式,一种是从FilterAttribute
    (抽象类属性)以及接口 IActionFilterIResultFilter中继承并实现。另一种是我们经
    常提到的从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/


     

  • 相关阅读:
    思维导图
    网络面经
    2.17 C++ 专项练习 错题复盘
    C++面经
    2.15 C++专项练习 错题复盘
    uboot下读取flash,上传tftp服务器、下载
    Hi3516EV100烧录出厂固件
    用Hi3518EV200板当spi烧录器
    生而为人,我很抱歉!深夜爬虫, 我很抱歉 ,附微信 “ 网抑云” 公众号爬虫教程!
    阿里HR: 你会 Android 实现侧滑菜单-design吗? CN看了,原来这么简单呀!
  • 原文地址:https://www.cnblogs.com/daizhj/p/1453885.html
Copyright © 2011-2022 走看看