HttpModule应用
由做网站操作日志想到的HttpModule应用
背景
在以前的Web项目中,记录用户操作日志,总是在方法里,加一行代码,记录此时用户操作类型与相关信息。该记录日志的方法对原来的业务操作侵入性较强,也比较零散,不便于查看和管理。那么有没有更加通用点的方法呢。
同事建议我,写个HttpModule,能够得到请求的Http报文,同时获取到输出的Http报文,这样大致上能够分析出请求的行为了。最初对HttpModule很陌生,一直也没机会用到,故开始对这个方法,有点抵触。后来利用了强大的搜索引擎,发现确实有人向这方面做出了努力。如《初涉电子商务系统开发随想--第二篇-基于asp.net Mvc的通用日志管理方法》。我也来写的试试吧。
HttpModule
首先就必须先了解HttpModule,了解它的事件发生顺序,在什么时候又可以访问到Session,如何获取到Http输入流和输出流等。下面是参考的内容:
ASP.NET中httpmodules与httphandlers全解析
最后我选择了 AcquireRequestState 这个事件,因为在其中可以访问到Session,以备不时之需。Module代码如下:
HttpFilterModule
Http输入流和输出流
读取Http的输入流很简单,相比如果之前有做Http接口的朋友,很清楚。直接在Request.InputStream 就可以读取到全部内容,那么输入内容是不是也这样方便呢?再次感谢强大的搜索引擎,关于读取输出流的内容,见 《Asp.net2.0 中自定义过滤器对Response内容进行处理》。摘抄部分如下:
在代码设计前分析了一下,前三个都很好解决,对于截获服务器返回的正文,准备用HttpResponse 对象中的Output 和 OutputStream 属性输出信息来解决。 可是在正式编码的过程中,发现Output和OutputStream 并不是想像中可以直接把数据转出取回,耗费了近两天的时间,想尽了一切办法可还是仅仅可以追加内容并无法读取。 在网上查阅到,对于HttpResponse 对象,仅仅可以使用过滤器来对其中将要输出的内容进行修改。
这个过滤器要继承自Stream 类,并要实现其中的虚方法。看来之前企图使用HttpWriter,TextWriter,Stream,HttpStream 这些类来转出数据完全是错误的。
自定义HttpFileterStream 替换Response.Filter ,而网页在输出时,一定会调用 Write 方法,而Write方法里的参数,则是我们需要的东西了。
这样输入流和输出流就能获取到了。
如何动态加载日志处理类型
既然能够拿到每次请求的输入流和输出流,接下来则是将这些需要的信息交给工厂类来操作。目前所处的项目是 MVC3.0,前端采用extjs,控制器输出的则是各种Json。结合项目情况,我仅仅需要将 Controller和Action得到,然后交给指定的Log处理类,它来处理,流程基本上就走完了。
但在实际的编码过程中,遇到一点问题,则是怎么更好的去处理这个映射关系。于是想到mvc,它最初得到的不也是url地址,只不过该url 包含了Controller与Action信息,那它是如何找到对应的Controller对象呢。这次强大的搜索引擎也没能解决我的问题,那就只能自己动手。这里有个插曲,是控制器的命名空间可以自己任意定义,mvc也能根据控制器的名字找到它。自己也想实现这样的效果,最后下载mvc的源代码单步调试,看到的结果吓了我一跳,想来也是在情理之中。
mvc在初始化时,会加载所有的程序集,遍历程序集的所有类型,然后在做筛选,筛选后并将类型缓存起来。摘抄类如下:
不仅控制器的类型是这样加载的,Area等好多类型都是这样加载的,mvc内部大量使用静态变量缓存数据。
既然这样,我也想采用类似的机制,在所有程序集中搜索继承IFilter的类型。
Attribute的应用
由于我最后设想的是,将每次请求的行为,映射到一个或多个日志处理上。所以最后在方法上定义了属性进行识别。看看FilterAttribute的定义:

[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class FilterMethodAttribute : Attribute
{
public FilterMethodAttribute(string controllerName, params string[] actionName)
{
this.controllerName = controllerName;
this.actionName = actionName;
}
//需要过滤的控制器名称
public string controllerName { get; set; }
public string[] actionName { get; set; }
}

这样就可以监控一个Controller上的多个Action,由于设置了该属性可以重复,故可以监控多个控制器上的多个Action。
日志处理写法
除了方法必须包含一个FilterContext参数,并且在方法上指定FilterMethod属性,此外没有任何约束。看看典型的实例:

public class Log1 : IFilter
{
[FilterMethod("Home", "Index")]
public void Log_Login(FilterContext context)
{
var path = HttpContext.Current.Server.MapPath("~/log1.log");
var content = string.Format("登陆ID:{0} 登陆人:{1}\r\n", context.IP, context.UserName);
File.AppendAllText(path, content);
}
}

回顾
现在,整个流程则是,程序在初始化时,会在所有的程序集中搜索继承IFilter的类型,然后在该类型中找到定义了FilterMethod属性的方法,判断它要监控哪些控制器,之后将该方法生成一个强类型的委托,缓存到Dictionary中,便于工厂查找。
最初是为了实现日志应用,后来发现越做越不像日志处理,就类似一个通用的模块,可以得到Http的输入流和输出流,其中若需要更多,可根据情况修改代码。而拿到这些数据,我们可以做很多应用,而日志处理只是一种应用。
其他
1.若日志等应用处理,无需更改输出内容,则可以将处理放入线程池中执行。
2.若需要做安全检测、权限验证,则可以直接使用MVC提供的Filter,虽然不能读取输出流,但是可以改写和追加。
3.Module需要被加载,必须在WebConfig中 system.webServer 节点下进行配置,若有多个HttpModule,加载顺序则是根据配置的顺序来加载的。
4.源码中AssemblyType文件夹存放的是MVC源代码中的类型搜索相关类,可以直接拿出来使用。HttpFilter文件夹存放的是实现该模块的相关类。而LogFilter就是日志应用了。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
感谢阅读,希望这篇文章能给你带来帮助!
HttpModule应用的更多相关文章
- ASP.NET使用HttpModule压缩并删除空白Html请求
当我们压缩我的Response后再传到Client端时,可以明显节省宽带. 提升Site的性能. 现在的浏览器大部分都支持Gzip,Deflate压缩. 同时我们还可以删除一些空白段,空行,注释等以使 ...
- [转]HttpModule的认识
HttpModule是向实现类提供模块初始化和处置事件.当一个HTTP请求到达HttpModule时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于H ...
- [转]ASP.NET应用程序生命周期趣谈(三) HttpModule
在之前的文章中,我们提到过P_Module(HttpModule)这个能干的程序员哥们儿,它通过在项目经理HttpApplication那里得到的授权,插手整个应用程序级别的事件处理.所有的HttpM ...
- 基于HttpModule的简单.NET网站授权方案
摘要 本文介绍一种入门级的网站授权(注:这里所指的授权指的是注册码效果,而不是网站登陆时的身份授权)方案,仅供学习交流及对付小白客户使用.复杂的网站授权涉及网站加密等一系列复杂的技术,不做本文介绍内容 ...
- httphandler和httpmodule的区别
ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后,仍经过Pi ...
- 你必须知道ASP.NET知识------关于动态注册httpmodule(对不起汤姆大叔)
一.关于动态注册的问题 很多人看过汤姆大叔的MVC之前的那点事儿系列(6):动态注册HttpModule ,其实汤姆大叔没有发现httpmodule动态注册的根本机制在哪里. 亦即:怎么动态注册?为什 ...
- Asp.Net通过HttpModule实现URL重写
首先总结一下为什么要对URL进行Rewrite,比如我可以把/Default.aspx?param=3替换成/Home/Default/3(类似mvc). 一.缩短url,隐藏实际路径提高安全性; 二 ...
- Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, ...
- 部署网站出现System.ServiceModel.Activation.HttpModule错误
1. 部署网站到IIS7.5,Window 2008的时候出现这个错误 2. 错误信息 Server Error in '/' Application. Could not load type 'Sy ...
- HttpModule的认识
1.asp.net的HTTP请求处理过程 说明: (1).客户端浏览器向服务器发出一个http请求,此请求会被inetinfo.exe进程截获,然后转交给aspnet_isapi.dll进程,接着它又 ...
随机推荐
- char* 和char[]差异
从因特网以下内容.笔者和总结汇总. 1. 问题介绍 问题引入: 在实习过程中发现了一个曾经一直默认的错误.相同char *c = "abc"和char c[]="abc& ...
- 创建自定义的Middleware中间件
创建自定义的Middleware中间件 阅读目录 何为Middleware中间件 使用Inline方式注册Middleware 使用Inline+ AppFunc方式注册Middleware 定义原生 ...
- NYOJ 904 search(stable_sort函数的应用)
描述 游戏积分的排行榜出来了,小z想看看得某个积分的人是谁.但是由于人数很多,他自己找很浪费时间,所以他想请你帮忙写一个程序,能快速的帮他找到他想要找的人 输入 多组测试数据,第一行有一个数T,表 ...
- 第23章 访问者模式(Visitor Pattern)
原文 第23章 访问者模式(Visitor Pattern) 访问者模式 导读:访问者模式是我个人认为所有行为模式中最为复杂的一种模式了,这个模式可能看一遍会看不懂,我也翻了好几个例子,依然不能很好的 ...
- e.target 和 e.srcElement 的使用问题
ie 下的event.srcElement从字面上可以看出来有以下关键字:事件.源(它的意思就是:当前事件的源), 我们可以调用他的各种属性就像:document.getElementById(&qu ...
- php_cawler_html嵌套标签清洗
主要处理 嵌套 div,正则无法很好的处理清洗 比如文本: 想要移除 class =quizPutTag 的div ,内部可能嵌套的还有未知层级的div[前提是html文本段是闭合标签的] 这是< ...
- java-新浪微博开放平台——话题跟踪
代码 网盘地址:http://pan.baidu.com/s/1pJ1D0Kz
- winform屏幕截图
原文:winform屏幕截图 屏幕截图是一个比较常用的功能,在项目中出现的比例也比较高,至少我做过的每个项目都有屏幕截图这个功能,从全屏截图到区域截图都有出现过.当然区域截图已然包含了全屏截图. 全屏 ...
- ExtJs--15--Ext.is*各种类型推断的方法,简单看源代码就能够明确了
/** * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if ...
- jmgraph前端画图组件(html5版)
原文:jmgraph前端画图组件(html5版) jmgraph是一个基于html5的WEB前端画图组件. 前端画图对象控件化,支持鼠标和健盘事件响应,可对单个控件样式设定,支 ...