利用HttpModule做流量记录

来源:互联网 发布:打印照片排版软件 编辑:程序博客网 时间:2024/05/16 09:52

简单需求:
记录用户访问网站的地址,浏览器,时间,用户信息等信息。

原来打算用免费的流量统计系统,但是考虑到分析数据最好自己保留,所以最终决定自己做。首要一步就是记录流量信息。
前面《利用HttpModule实现浏览器版本控制》就是在利用HttpModule记录流量信息时做的衍生,同时也可以实现页面编程无需任何附加代码。不需要加JS代码段也不要附加任何CS代码段。并且模块相互独立,可以重复利用,也利于不需要时分离。


FlowEntity.cs(信息实体)——————————————————————————————————————————————
using System;
using System.Collections.Generic;
using System.Text;

namespace Xingmai.WebSite.FlowStatistics
{
    /// <summary>
    /// 流量记录单个记录集
    /// </summary>
    public class FlowEntity
    {
        private FlowAgentEntity _AgentInfo;
        private FlowUserInfoEntity _UserInfo;
        private FlowRequestEntity _RequestInfo;

        /// <summary>
        /// 用户基本信息
        /// </summary>
        public FlowUserInfoEntity UserInfo
        {
            get
            {
                return _UserInfo;
            }
            set
            {
                _UserInfo = value;
            }
        }

        /// <summary>
        /// 用户代理信息
        /// </summary>
        public FlowAgentEntity AgentInfo
        {
            get
            {
                return _AgentInfo;
            }
            set
            {
                _AgentInfo = value;
            }
        }

        /// <summary>
        /// 用户访问信息
        /// </summary>
        public FlowRequestEntity RequestInfo
        {
            get
            {
                return _RequestInfo;
            }
            set
            {
                _RequestInfo = value;
            }
        }
    }

    /// <summary>
    /// 用户基本信息实体
    /// </summary>
    public class FlowUserInfoEntity
    {
        private int _UserID;
        private string _UserName;

        /// <summary>
        /// 用户ID
        /// </summary>
        public int UserID
        {
            get
            {
                return _UserID;
            }
            set
            {
                _UserID = value;
            }
        }

        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName
        {
            get
            {
                return _UserName;
            }
            set
            {
                _UserName = value;
            }
        }
    }

    /// <summary>
    /// 用户代理信息实体
    /// </summary>
    public class FlowAgentEntity
    {
        private int _BrowserMajorVer;
        private double _BrowserMinorVer;
        private string _BrowserName;
        private string _HostName;
        private string _IP;
        private string _Language;
        private string _PlatForm;

        /// <summary>
        /// 用户访问IP
        /// </summary>
        public string IP
        {
            get
            {
                return _IP;
            }
            set
            {
                _IP = value;
            }
        }

        /// <summary>
        /// 用户主机名
        /// </summary>
        public string HostName
        {
            get
            {
                return _HostName;
            }
            set
            {
                _HostName = value;
            }
        }

        /// <summary>
        /// 用户语种
        /// </summary>
        public string Language
        {
            get
            {
                return _Language;
            }
            set
            {
                _Language = value;
            }
        }

        /// <summary>
        /// 用户操作系统平台
        /// </summary>
        public string PlatForm
        {
            get
            {
                return _PlatForm;
            }
            set
            {
                _PlatForm = value;
            }
        }

        /// <summary>
        /// 浏览器名称
        /// </summary>
        public string BrowserName
        {
            get
            {
                return _BrowserName;
            }
            set
            {
                _BrowserName = value;
            }
        }

        /// <summary>
        /// 浏览器主版本号
        /// </summary>
        public int BrowserMajorVer
        {
            get
            {
                return _BrowserMajorVer;
            }
            set
            {
                _BrowserMajorVer = value;
            }
        }

        /// <summary>
        /// 浏览器次版本号
        /// </summary>
        public double BrowserMinorVer
        {
            get
            {
                return _BrowserMinorVer;
            }
            set
            {
                _BrowserMinorVer = value;
            }
        }
    }

    /// <summary>
    /// 用户访问信息实体
    /// </summary>
    public class FlowRequestEntity
    {
        private DateTime _RequestDateTime;
        private string _RequestUrl;

        /// <summary>
        /// 访问时间
        /// </summary>
        public DateTime RequestDateTime
        {
            get
            {
                return _RequestDateTime;
            }
            set
            {
                _RequestDateTime = value;
            }
        }

        /// <summary>
        /// 访问地址
        /// </summary>
        public string RequestUrl
        {
            get
            {
                return _RequestUrl;
            }
            set
            {
                _RequestUrl = value;
            }
        }
    }
}

FlowModule.cs(Module模块)——————————————————————————————————————————————

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;
using System.IO;
using System.Configuration;

namespace Xingmai.WebSite.FlowStatistics
{
    public class FlowModule : IHttpModule
    {
        #region 内部似有变量

        private string[] FlowType;
        private FlowDAL dal;

        #endregion

        #region 内部自有方法

        private bool IsFlowType(string strUrl)
        {
            foreach (string strFlowType in FlowType)
            {
                if (strUrl.ToLower().Contains(strFlowType))
                {
                    return true;
                }
            }
            return false;
        }


        #endregion

        #region 实例构造函数

        public FlowModule()
        {
            //读取记录数据的类型
            try
            {
                FlowType = ConfigurationManager.AppSettings["FlowType"].Split((new string[] { "|" }), StringSplitOptions.RemoveEmptyEntries);
            }
            catch (System.Configuration.ConfigurationErrorsException ex)
            {
                throw new Exception(string.Format("请正确配置web.config AppSetting[BrowserChooserPage]节点,系统错误提示:{0}", ex.Message));
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
            //实例化数据层
            dal = new FlowDAL();
        }

        #endregion

        #region IHttpModule 成员


        public void Init(HttpApplication application)
        {
            
//这里8月29日有更改,这个BeginRequest事件里面无法获取到Session,疏忽,望大家谅解!应改用AcquireRequestState事件!
            //
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
            application.AcquireRequestState+=new EventHandler(application_AcquireRequestState);
        }

        private void application_AcquireRequestState(Object source, EventArgs e)
        {

            HttpApplication Application = (HttpApplication)source;
            HttpContext ctx = Application.Context;
            
            if(!IsFlowType(ctx.Request.Url.AbsoluteUri))
                 return;


            FlowUserInfoEntity user = new FlowUserInfoEntity();
            if (ctx.Session["UserInfo"] != null)
            {
                user.UserID = 1;
                user.UserName = "ceshi";
            }
            else
            {
                user.UserID = 0;
                user.UserName = "UnKnown";
            }

            FlowRequestEntity request = new FlowRequestEntity();
            request.RequestDateTime = DateTime.Now;
            request.RequestUrl = ctx.Request.Url.AbsoluteUri;

            FlowAgentEntity agent = new FlowAgentEntity();
            agent.BrowserMajorVer = ctx.Request.Browser.MajorVersion;
            agent.BrowserMinorVer = ctx.Request.Browser.MinorVersion;
            agent.BrowserName = ctx.Request.Browser.Browser;
            agent.HostName = ctx.Request.UserHostName;
            agent.IP = ctx.Request.UserHostAddress;
            agent.Language = ctx.Request.UserLanguages[0];
            agent.PlatForm = ctx.Request.Browser.Platform;

            FlowEntity entity = new FlowEntity();
            entity.AgentInfo = agent;
            entity.UserInfo = user;
            entity.RequestInfo = request;
            dal.Record(entity);
        }

        public void Dispose()
        {

        }

        #endregion
    }
}

FlowDAL.cs(数据存储层,可以根据自己的需要重写此层。想存数据库也行,XML也行)—————————————————————————

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Configuration;

namespace Xingmai.WebSite.FlowStatistics
{
    /// <summary>
    /// 流量统计数据层
    /// </summary>
    public class FlowDAL
    {
        private SqlConnection _conn;
   
        public FlowDAL()
        {
            try
            {
                _conn = new SqlConnection(ConfigurationManager.ConnectionStrings["FlowConn"].ConnectionString);
                _conn.Open();
            }
            catch (ConfigurationErrorsException ex)
            {
                throw new Exception(string.Format("请正确配置web.config AppSetting[BrowserChooserPage]节点,系统错误提示:{0}", ex.Message));
            }
            catch (SqlException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 记录流量信息
        /// </summary>
        /// <param name="flowEntity">流量记录实体</param>
        public void Record(FlowEntity flowEntity)
        {
            //判断连接是否为打开状态
            if (_conn.State = !ConnectionState.Open)
                _conn.Open();

     ///////记录代码略////////
        }

        public void Dispose()
        {
            _conn.Close();
        }
    }
}

web.config <system.web> <httpModules> 配置节点—————————————————————————————————
<add name="FlowModule" type="Xingmai.WebSite.FlowStatistics.FlowModule, Xingmai.WebSite.FlowStatistics"/>

web.config <appSettings> 配置节点 (需要记录的类型)——————————————————————————————
<add key="FlowType" value=".htm|.html|.aspx|.asmx"/>

web.config <connectionStrings>配置节点 (记录数据库的连接,如果你重写的数据层,那么这个可要可不要)——————
<add name="FlowConn" connectionString="" providerName="System.Data.SqlClient"/>




关于IHttpModule(MSDN信息)
自定义 HTTP 模块阐释了 HTTP 模块的基本功能。在响应下面两个事件时调用该模块:BeginRequest 事件和 EndRequest 事件。这使该模块可以在处理页请求之前和之后运行。在这种情况下,

该模块向请求的 ASP.NET 网页的任一 HTTP 请求开头处添加一条消息,并在处理请求后添加另一条消息。

注意
BeginRequest 和 EndRequest 事件只是在处理页期间发生的两个事件。有关在处理页期间引发的事件的更多信息,请参见 ASP.NET 网页中的服务器事件处理。

每个事件处理程序都编写为模块的私有方法。在引发已注册事件时,ASP.NET 调用该模块中适当的处理程序方法,该方法将信息写入 ASP.NET 网页中。

创建自定义 HTTP 模块类
如果网站还没有 App_Code 文件夹,请在该站点的根目录下创建这样的一个文件夹。

在 App_Code 目录中,创建一个名为  HelloWorldModule.cs的类文件。

注意
或者,可以将 HelloWorldModule 类编译到一个库中,并将得到的 .dll 文件放在 Web 应用程序的 Bin 目录中。

将以下代码添加到该类文件中:

C# 
public class HelloWorldModule : IHttpModule
{
    public HelloWorldModule()
    {
    }

    public String ModuleName
    {
        get { return "HelloWorldModule"; }
    }

    // In the Init function, register for HttpApplication
    // events by adding your handlers.
    public void Init(HttpApplication application)
    {
        application.BeginRequest +=
            (new EventHandler(this.Application_BeginRequest));
        application.EndRequest +=
            (new EventHandler(this.Application_EndRequest));
    }

    private void Application_BeginRequest(Object source,
         EventArgs e)
    {
    // Create HttpApplication and HttpContext objects to access
    // request and response properties.
        HttpApplication application = (HttpApplication)source;
        HttpContext context = application.Context;
        context.Response.Write("<h1><font color=red>
            HelloWorldModule: Beginning of Request
            </font></h1><hr>");
    }

    private void Application_EndRequest(Object source, EventArgs e)
    {
        HttpApplication application = (HttpApplication)source;
        HttpContext context = application.Context;
        context.Response.Write("<hr><h1><font color=red>
            HelloWorldModule: End of Request</font></h1>");
    }

    public void Dispose()
    {
    }
}
 
注册 HTTP 模块
在创建完 HelloWorldModule 类后,可以通过在 Web.config 文件中创建一项来注册该模块。

在 Web.config 文件中注册该模块
如果网站还没有 Web.config 文件,请在该站点的根目录下创建一个这样的文件。

将下面突出显示的代码添加到该 Web.config 文件中:

  复制代码
<configuration>
    <system.web>
        <httpModules>
          <add name="HelloWorldModule" type="HelloWorldModule"/>
        </httpModules>
    </system.web>
</configuration>
 

这段代码用 HelloWorldModule 的类名和模块名注册该模块。

测试自定义 HTTP 模块
创建并注册完自定义 HTTP 模块后,可以对它进行测试。

测试自定义 HTTP 模块
在应用程序中创建一个 Default.aspx 页。

在浏览器中请求该 Default.aspx 页。

HTTP 模块会将一个字符串追加到响应的开头和结尾。在请求扩展名指定为 ASP.NET 类型的文件时,该模块将会自动运行。



+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
后续《利用HttpModule做流量记录 补充》对方案进行了一些补充

如果选用从Session中传入用户信息或者其他需要记录的信息,请在记录前加判断(2007年8月29日20:34:43增加)
 if (ctx.Handler is Page || ctx.Handler is WebService)
根据需要选用Page还是WebService。
调试过程中发现,如果是其他的类型可能不创建Session,这时从Session读取数据发生错误,造成整个请求中断引起请求失效。这样其他的Module可能不能执行造成页面上一些需要生成的东西无法生成,例如Asp.net Ajax从WebService生成的脚本类型注册等,引发错误!
尽量捕捉错误,因为这些错误可能不会直接爆出,引发请求中断,让人有的时候摸不着头脑!

原创粉丝点击