一个使用HttpModule监听URL请求并保存到数据库的例子

4 篇文章 0 订阅

httpmodule和httphandler的原理,我记得在stackoverflow里有个形象的比喻,请求如果是辆火车,httpmodule就是中途的站点, handler就是终点站。详细原理可参考https://www.cnblogs.com/caoyc/p/6409062.html

使用HttpModule可以在不改动现有代码的情况下实现一些功能,比如监听URL请求,获取session的值,并写入到数据库里,下面说说方法和例子

 

1.创建一个.net的dll项目  

2. 创建一个实现IHttpModule的类,例子代码如下

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using System.Web.SessionState;
using System.Xml.Linq;

namespace LogRequestModule
{
    public class LogHttpModule : IHttpModule, IRegisteredObject
    {
        public void Dispose()
        {
        }

        public class LogData
        {
            public string url { get; set; }
            public string sessionvalue1 { get; set; }
        }

        public static AutoResetEvent logEvent = new AutoResetEvent(true);
        public static ConcurrentQueue<LogData> queue = new ConcurrentQueue<LogData>();
        public static bool runningWriteLog = true;
        public static void WriteLog()
        {
            //Get connection string from web.config file  
            var connStringSetting = ConfigurationManager.ConnectionStrings["LogModuleDBConnection"];
            if (connStringSetting == null)
                return;

            while (runningWriteLog)
            {
                try
                {
                    LogData logData;
                    using (var conn = new SqlConnection(connStringSetting.ConnectionString))
                    {
                        using (var cmd = new SqlCommand("SP_Log", conn))
                        {
                            cmd.CommandType = CommandType.StoredProcedure;
                            cmd.Parameters.Add("url", SqlDbType.NVarChar, 1024);
                            cmd.Parameters.Add("sessionvalue1", SqlDbType.NVarChar, 32);
                            conn.Open();
                            while (queue.TryDequeue(out logData))
                            {
                                cmd.Parameters["url"].Value = logData.url;
                                cmd.Parameters["sessionvalue1"].Value = logData.sessionvalue1;
                                cmd.ExecuteNonQuery();
                            }
                        }
                        conn.Close();
                    }
                    logEvent.WaitOne(3000);
                }
                catch (Exception ex)
                {

                }
            }
        }

        public void Init(HttpApplication context)
        {
            HostingEnvironment.RegisterObject(this);
            Task.Factory.StartNew(WriteLog);
            context.PostAcquireRequestState += new EventHandler(Application_PostAcquireRequestState);
            context.PostMapRequestHandler += new EventHandler(Application_PostMapRequestHandler);

        }
        
        private void Application_PostMapRequestHandler(object source, EventArgs e)
        {
            HttpApplication app = (HttpApplication) source;

            if (app.Context.Handler is IReadOnlySessionState || app.Context.Handler is IRequiresSessionState)
            {
                // no need to replace the current handler
                return;
            }

            // swap the current handler
            app.Context.Handler = new TempSessionHttpHandler(app.Context.Handler);
        }

        private void Application_PostAcquireRequestState(object source, EventArgs e)
        {
            HttpApplication app = (HttpApplication) source;

            var resourceHttpHandler = HttpContext.Current.Handler as TempSessionHttpHandler;

            if (resourceHttpHandler != null)
            {
                // set the original handler back
                HttpContext.Current.Handler = resourceHttpHandler.OriginalHandler;
            }

            // -> at this point session state should be available

           //  Debug.Assert(app.Session != null, "it did not work :(");
             //Log operation goes here
             HttpContext context = app.Context;
             string url = context.Request.Url.OriginalString;
             var reqData = new LogData
             {
                 url = url,
                 sessionvalue1 = app.Session["sessionvalue1"] as string,
             };
             queue.Enqueue(reqData);
             logEvent.Set();

        }


        public void Stop(bool immediate)
        {
            runningWriteLog = false;
        }
    }
}

如果要获取session值,还需要定义一个handler,例子代码如下

// a temp handler used to force the SessionStateModule to load session state
using System;
using System.Web;
using System.Web.SessionState;

namespace LogModule
{

    public class TempSessionHttpHandler : IHttpHandler, IRequiresSessionState
    {
        internal readonly IHttpHandler OriginalHandler;

        public TempSessionHttpHandler(IHttpHandler originalHandler)
        {
            OriginalHandler = originalHandler;
        }

        public void ProcessRequest(HttpContext context)
        {
            // do not worry, ProcessRequest() will not be called, but let's be safe
            throw new InvalidOperationException("MyHttpHandler cannot process requests.");
        }

        public bool IsReusable
        {
            // IsReusable must be set to false since class has a member!
            get { return false; }
        }
    }
}

3. 编译好后生成dll, 部署到要监听的站点的bin目录下

4. 在web.config增加module配置

修改该站点的web.config文件

   在modules配置节点下增加一条记录,如下

   <system.webServer>

    <modules runAllManagedModulesForAllRequests="true" >

<add name="LogHttpModule" type="LogModule.LogHttpModule,LogModule"/>

</modules>

     </system.webServer>

  

  注意:如果该站点下如果有子站点,需要在各个子站点增加remove记录,否则会导致子站点继承父站点配置而找不到module报错。如下

<!--Web Server-->

  <system.webServer>

    <modules runAllManagedModulesForAllRequests="true" >

<remove name="LogHttpModule" />

    </modules>

  </system.webServer>

5. 添加其他配置,如数据库连接,创建数据库存储过程等,这里就不再赘述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值