• mvc基础系列说谈(9)——修饰标签(修饰属性,过滤器)(中)


    在上一篇中,介绍了

    AcceptVerbsActionNameNonActionOutputCacheValidateInputHandleError这几个修饰标签。它们的父类有所不同。例如:

    AcceptVerbs 标签(类)从ActionMethodSelectorAttribute类派生;NonActionActionMethodSelectorAttribute派生。

     

    然后,如HandleError它的定义是这样的:

    public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
    {
        
    //Fields
        private const string _defaultView = "Error";
        
    private Type _exceptionType;
        
    private string _master;
        
    private string _view; 

        
    //Methods
        public HandleErrorAttribute();
        
    public virtual void OnException(ExceptionContext filterContext);

        
    //Properties
        public Type ExceptionType { getset; }
        
    public string Master { getset; }
        
    public string View { getset; }
    }

     

    它继承了FilterAttribute类,且实现了IExceptionFilter 接口。

     

    asp.net MVC框架支持以下几类过滤器:
    ·AuthorizeAttribute
    用于实现用户验证及对动作访问的授权。

    ·Action过滤器

    ·Result过滤器

    ·Exception过滤器

    并提供以下几个接口:

    public interface IActionFilter
    {
        
    // Methods
        void OnActionExecuted(ActionExecutedContext filterContext);
        
    void OnActionExecuting(ActionExecutingContext filterContext);
    }

     

    public interface IResultFilter
    {
        
    // Methods
        void OnResultExecuted(ResultExecutedContext filterContext);
        
    void OnResultExecuting(ResultExecutingContext filterContext);
    }
    public interface IExceptionFilter
    {
        
    // Methods
        void OnException(ExceptionContext filterContext);
    }

     

    public interface IAuthorizationFilter
    {
        
    // Methods
        void OnAuthorization(AuthorizationContext filterContext);
    }

    另外还有一个标签:

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
    Inherited 
    = true, AllowMultiple = false)]
    public abstract class FilterAttribute : Attribute
    {
        
    private int _order;
        
    protected FilterAttribute();
        
    public int Order { getset; }
    }

    如果要实现一个自定义过滤器,须实现这个标签和一个以上的接口。MVC还提供了一个ActionFilterAttributen属性(类),它已经实现了IActionFilter, IresultFilter这两个接口,然后可以重载它们的方法来自定义过滤器。

    (一)日志记录

    现在做一个自定义的日志过滤器,用于记录日志。实现的目标很简单:当访问此页时,记录当前的时间。这个直接从ActionFilterAttribute 派生。

    在实现之前,得说下执行顺序:

    OnActionExecuting – Action执行之前调用。

    OnActionExecuted – Action执行之后调用。

    OnResultExecuting – Result产生之前调用。

    OnResultExecuted

     

    现在要做的是在ActionExecuting事件中记录时间,在ResultExecuted事件中记录时间,即在自定义过滤器中重载其中两个方法即可:

    public class DateLogFilter : ActionFilterAttribute
    {
        
    public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            Log(
    "ActionExecuting" + DateTime.Now.ToString());
        }

        
    public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            Log(
    "ResultExecuted " + DateTime.Now.ToString());
        }

        
    private void Log(string strMessage)
        {
            strMessage.WriteFile(
    @"K:\logs\""log.txt");
        }
    }

    其中的Log方法用于记录内容。

    用的时候就是以修饰标签的方式声明即可:

    [DateLogFilter]
    public ActionResult NewsList()
    {
        ……
    }

    这个简单的日志记录过滤器就完成了。这个日志过滤器的定义是没有多大意义的,它只用来演示自定义过滤器。

    (二)实现图片防盗

    图片防盗的原理是利用Http头中的Referer键来实现的。对于资源文件来说,它记录资源文件的引用地址:

    请见:

    http://www.cnblogs.com/jams742003/archive/2010/02/01/1660917.html 

    例如:http://192.168.1.105:8029/images/a1.gif

    这个地址有一个a1.gif图片资源文件。而在另一个站中引用时:

    <img src="http://192.168.1.105:8029/images/a1.gif" />

    此时的Http头中截取部分键对:

    ·(Request-Line):GET /images/a1.gif HTTP/1.1
    ·Host:192.168.1.105:8029
    ·Referer:http://localhost:20372/web2/Test.aspx

    其中的Host为资源的地址,而Referer为引用图片的地址。这两个地址不同,所以可以进行防盗处理了。

    WebForm模型中,通过自定义HttpHandler来实现防盗处理,而HttpHandlerHttp请求的最终处理中心。例如,通过ashx资源文件进行防盗,因为这个类从IhttpHandler派生的。或者直接以HttpHandler来进行全局资源防盗处理。

    1)实现IhttpHandler接口

    实现public void ProcessRequest(HttpContext context) 这个方法。通过Http上下文来判断Http头中的HostReferer键值:context.Request.UrlReferrer.Host

    2)注册Handler 

    <httpHandlers>
        
    <add path="*.gif" verb="*" type="GifHandler"/>
    </httpHandlers>

    3)在IIS中添加Gif文件映射

    以上三项完成后就可以了。

    MVC中实现防盗原理也是这样的。

    现在还通过以前介绍的方法来实现并通过测试。

    现在先看一个图片访问地址:

    http://192.168.1.105:8196/Contents/images/a1.gif

    这个地址是一张图片,然后,在MVC中,按路由来分析一下它的情况:

    当访问这个地址时(URL),会路由到Contents控制器,并执行images动作,且向这个动作传递了一个a1.gif的字串参数。于是分别创建:

    (01)控制器Contents

    public ActionResult images(string strFilename)
    {
        
    return File("http://www.cnblogs.com/content/images/"+strFilename, "image/gif");
    }

    这张图片放在content文件夹中的images文件夹中

    这个动作就是返回图片文件。其中File方法是控制器的一个方法,用于返回ActionResult类型对象。

    (02)过滤器

    自定义过滤器,可以直接从ActionFilterAttribute类派生,重载它的方法。这里只重载OnActionExecuting这个方法。

    实现为:

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpContextBase httpContext 
    = filterContext.HttpContext;
        
    if (null != httpContext.Request.UrlReferrer)
        {
            
    string serverDomain = httpContext.Request.Url.Host;
            
    string refDomain = httpContext.Request.UrlReferrer.Host; 

            
    if(serverDomain.Contains(refDomain))
            {
               
    return;//如果根域名相同就返回
             }

            ContentResult cr 
    = new ContentResult();
            
    if (FileType == FileType.Image)
            {
               cr.ContentType 
    = "image/jpeg";
               FileInfo fi 
    = new FileInfo(httpContext.Server.MapPath("~/Content/images/z1.gif")); 
               httpContext.Response.WriteFile(fi.FullName);
            }

            filterContext.Result 
    = cr;
        }    

    }

    现在分析一下这个方法:

    原理很简单,在Http请求时,资源文件和html是分步进行,例如,一张html中带有一张图片,那么,它会先请求html,然后请求图片,这个在

    http://www.cnblogs.com/jams742003/archive/2010/02/01/1660917.html

    中已经分析过。在第一次请求中,在http头中hostreferer两个键值并不是全有的,也就是在第二次请求中(请求图片)时,两个值才全有。那么,如果第一次请求时(请求html),那么要判断:

    if (null != httpContext.Request.UrlReferrer)

    如果不为无(一般我把null叫做无,而不叫空),那么才确定是资源请求。 

    然后:

    string serverDomain = httpContext.Request.Url.Host;
    string refDomain = httpContext.Request.UrlReferrer.Host;

     这两句用于得到HostReferer键值

    于是,如果是本网站访问的,那么两个值应该相等(这两个值要分析,它们的主体部分应该相同),这里粗略的判断:

    if(serverDomain.Contains(refDomain))
    {
        
    return;//如果根域名相同就返回
    }

    如果两部分相同,那么直接返回即可,不再做处理。

    如果不相同,说明是别的网站访问的,那么:

    if (FileType == FileType.Image)
    {
        cr.ContentType 
    = "image/jpeg";
        FileInfo fi 
    = 
        
    new FileInfo(httpContext.Server.MapPath("~/Content/images/z1.gif"));
        httpContext.Response.WriteFile(fi.FullName);

    }

    如果是图片的话,返回防盗图片给他即可。这里的contenttype并不严格。

    这个过滤器是以修饰标签形式声明。

    (03)为动作添加修饰

    [SelfFilter(FileType.Image)]
    public ActionResult images(string strFilename)
    {
       
    return 
       File(
    "http://www.cnblogs.com/content/images/"+strFilename, "image/gif");
    }

     

    现在就是这种情况,其中SelfFilter是自定义的过滤器(一个从ActionFilterAttribute派生的属性类),

    为这个属性类还要添加一个一个参数的构造器,它是FileType枚举类型。

    public SelfFilter(FileType fileType)
    {
        
    this.FileType = fileType;
    }

     

    (04)测试

    在一个别的网站中添加文件,文件内容为:

    <form id="form1" runat="server">
        
    <div>
            
    <img src="http://192.168.1.105:8196/Contents/images/a1.gif" />
        
    </div>
    </form>

    然后会发现,显示的是一张防盗图片。

     

  • 相关阅读:
    前端日常开发常用功能系列之乱序
    ES6系列之箭头函数
    ES6系列之let/const及块级作用域
    前端日常开发常用功能系列之数组扁平
    前端日常开发常用功能系列之数组最值
    前端日常开发常用功能系列之拷贝
    前端日常开发常用功能系列之数组去重
    前端日常开发常用功能系列之节流
    前端日常开发常用功能系列之防抖
    数据库连接池优化配置(druid,dbcp,c3p0)
  • 原文地址:https://www.cnblogs.com/jams742003/p/1671395.html
Copyright © 2020-2023  润新知