昌吉编程网


python站群系统

MG孟买水晶球-使用NLog给Asp.NetCore做请求监控的方法_实用技巧

为了减少由于单个请求挂掉而拖垮整站的情况发生,给所有请求做统计是一个不错的解决方法,通过观察哪些请求的耗时比较长,我们就可以找到对应的接口、代码、数据表,做有针对性的优化可以提高效率。在  中我们可以通过注册一个 DelegatingHandler 来实现该功能。那在  中该如何实现呢?

一:比较 和  的请求管道

观察这两张图,可以发现他们非常的相似,都是管道式的设计,在  中,我们可以注册一系列的 DelegatingHandler 来处理请求上下文 HttpRequestMess**e,在  core 中,我们可以注册一系列中间件来处理请求上下文,他们两者从功能和意义上是非常相似的,我这里这里不会详细介绍各自的管道是如何的(这样的文章非常多,博客园随处可见),他们都完成了类似中间件的功能,只是在代码设计上有一点区别。

我们先看一段代码,新建一个项目,添加几个DelegatinHandler

然后在Global中注册

publicclassDelegatingHandler1:DelegatingHandler { protectedoverrideasyncTaskSendAsync(HttpRequestMess**erequest,CancellationTokencancellationToken) { Trace.WriteLine("DelegatingHandler1HashCode:"+this.GetHashCode()); Trace.WriteLine("DelegatingHandler1baseInnerHandlerHashCode:"+base.InnerHandler.GetHashCode()); Trace.WriteLine("DelegatingHandler1start"); varresponse=awaitbase.SendAsync(request,cancellationToken); Trace.WriteLine("DelegatingHandler1end"); returnresponse; } } publicclassDelegatingHandler2:DelegatingHandler { protectedoverrideasyncTaskSendAsync(HttpRequestMess**erequest,CancellationTokencancellationToken) { Trace.WriteLine("DelegatingHandler2HashCode:"+this.GetHashCode()); Trace.WriteLine("DelegatingHandler2baseInnerHandlerHashCode:"+base.InnerHandler.GetHashCode()); Trace.WriteLine("DelegatingHandler2start"); varresponse=awaitbase.SendAsync(request,cancellationToken); Trace.WriteLine("DelegatingHandler2end"); returnresponse; } } publicclassDelegatingHandler3:DelegatingHandler { protectedoverrideasyncTaskSendAsync(HttpRequestMess**erequest,CancellationTokencancellationToken) { Trace.WriteLine("DelegatingHandler3HashCode:"+this.GetHashCode()); Trace.WriteLine("DelegatingHandler3baseInnerHandlerHashCode:"+base.InnerHandler.GetHashCode()); Trace.WriteLine("DelegatingHandler3start"); varresponse=awaitbase.SendAsync(request,cancellationToken); Trace.WriteLine("DelegatingHandler3end"); returnresponse; } }

修改一下ValuesController

publicclassWebApiApplication:System.Web.HttpApplication { protectedvoidApplication_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); GlobalConfiguration.Configuration.Mess**eHandlers.Add(newDelegatingHandler1()); GlobalConfiguration.Configuration.Mess**eHandlers.Add(newDelegatingHandler2()); GlobalConfiguration.Configuration.Mess**eHandlers.Add(newDelegatingHandler3()); } }

启动后输入路径/api/values,我们可以在VS 的输出栏看到下面这些内容

publicclassValuesController:ApiController { //GETapi/values publicIEnumerableGet() { Trace.WriteLine("/api/values"); varhandlers=this.RequestContext.Configuration.Mess**eHandlers; returnnewstring[]{"value1","value2"}; } }

启动后输入路径/api/values,我们可以在VS的输出栏看到下面这些内容

DelegatingHandler1HashCode:

DelegatingHandler1baseInnerHandlerHashCode:

DelegatingHandler2HashCode:

DelegatingHandler2baseInnerHandlerHashCode:

DelegatingHandler3HashCode:

DelegatingHandler3baseInnerHandlerHashCode:

输出中我们可以看到 DelegatingHandler1 的InnerHandler 是 DelegatingHandler2,以此类推,在 DelegatingHandler3 的 InnerHandler 处理请求的时候就转发到了相关控制器,这里和.net core 中的中间件非常相似,在.net core中间件顺序是 RequestServicesContainerMiddleware(给请求上下文绑定容器)-> AuthenticationMiddleware(认证)->RouterMiddleware(路由以及MVC)

如果我们在 ValuesController 中观察表达式 this.RequestContext.Configuration.Mess**eHandlers 还可以看到最终处理请求的是一个 HttpRoutingDispatcher,最也是是分配到路由以及控制器来处理的,按照如此方式我们可以很容易在  webapi 中对请求统计。这里是比较简陋的,对此我们可以记录客户端和服务器更详细的信息,包括 IP 地址,http状态码,是否是认证用户等等,但是这篇主要是以  core 为主的,所以这里就不详细写下去了。