今天遇到一个问题,需要在API请求结束时,释放数据库链接,避免连接池被爆掉。
按照以往的经验,需要实现IHttpModule,具体不展开了。
但是实现了IHttpModule后,还得去web.config中增加配置,这有点麻烦了,就想有没有简单的办法。
其实是有的,就是在Global.asax.cs里面定义并实现 Application_EndRequest 方法,在这个方法里面去释放数据库连接即可,经过测试,确实能达到效果。
但是,为什么方法名必须是Application_EndRequest?在这之前真不知道为什么,只知道baidu上是这么说的,也能达到效果。
还好我有一点好奇心,想搞清楚是怎么回事情,就把net framework的源码拉下来(其实源代码在电脑里面已经躺了N年了) 分析了一下,以下是分析结果。
省略掉前面N个调用
第一个需要关注的是 HttpApplicationFactory.cs
从名字就知道,这是HttpApplication的工厂类,大家看看Gloabal.asax.cs 里面,是不是这样定义的
public class MvcApplication : System.Web.HttpApplication
{
.....
}
两者结合起来看,可以推测,HttpApplicationFactory 是用来获取 MvcApplication 实例的,实际情况也是如此 上代码(来自HttpApplicationFactory)
internal class HttpApplicationFactory{
internal const string applicationFileName = "global.asax"; //看到这里,就知道为什么入口文件是global.asax了,因为这里定义死了
...
private void EnsureInited() {
if (!_inited) {
lock (this) {
if (!_inited) {
Init();
_inited = true;
}
}
}
}
...
}
上面代码调用链路是EnsureInited->Init->CompileApplication->ReflectOnApplicationType->ReflectOnMethodInfoIfItLooksLikeEventHandler,核心作用是:将MvcApplication中,方法名包含下划线、方法参数为空或者有2个参数(第一个参数的类型是Object,第二个参数的类型是EventArgs) 的方法加入到_eventHandlerMethods 中
那么事件是怎么绑定的呢?继续上代码
internal class HttpApplicationFactory{
...
using (new ApplicationImpersonationContext()) {
app.InitInternal(context, _state, _eventHandlerMethods);
}
...
}
// HttpApplication.cs
public class HttpApplication{
...
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
.....
if (handlers != null)
HookupEventHandlersForApplicationAndModules(handlers);
.....
}
...
}
核心方法:HookupEventHandlersForApplicationAndModules,其作用就是将前面获取到的method与HttpApplication的Event进行绑定(前提是方法名是以Application_开头的)。
后面就是向IIS注册事件通知了,由于看不到IIS源码,具体怎么做的就不知道了。
最后安利一下,还是用net core吧,更加清晰、直观,谁用谁知道。