invoke方法是做啥的_使用 NLog 给 Asp.Net Core 做请求监控
為了減少由于單個(gè)請(qǐng)求掛掉而拖垮整站的情況發(fā)生,給所有請(qǐng)求做統(tǒng)計(jì)是一個(gè)不錯(cuò)的解決方法,通過(guò)觀察哪些請(qǐng)求的耗時(shí)比較長(zhǎng),我們就可以找到對(duì)應(yīng)的接口、代碼、數(shù)據(jù)表,做有針對(duì)性的優(yōu)化可以提高效率。在?asp.net web api?中我們可以通過(guò)注冊(cè)一個(gè)?DelegatingHandler?來(lái)實(shí)現(xiàn)該功能。那在?asp.net core?中該如何實(shí)現(xiàn)呢?
一:比較?asp.net web api 和?asp.net core?的請(qǐng)求管道
觀察這兩張圖,可以發(fā)現(xiàn)他們非常的相似,都是管道式的設(shè)計(jì),在?asp.net web api?中,我們可以注冊(cè)一系列的?DelegatingHandler?來(lái)處理請(qǐng)求上下文?HttpRequestMessage,在?asp.net?core?中,我們可以注冊(cè)一系列中間件來(lái)處理請(qǐng)求上下文,他們兩者從功能和意義上是非常相似的,我這里這里不會(huì)詳細(xì)介紹各自的管道是如何的(這樣的文章非常多,博客園隨處可見(jiàn)),他們都完成了類似中間件的功能,只是在代碼設(shè)計(jì)上有一點(diǎn)區(qū)別。
我們先看一段代碼,新建一個(gè) asp.net web api 項(xiàng)目,添加幾個(gè) DelegatinHandler
然后在 Global 中注冊(cè)
修改一下 ValuesController
啟動(dòng)后輸入路徑 /api/values,我們可以在VS?的輸出欄看到下面這些內(nèi)容
輸出中我們可以看到?DelegatingHandler1?的 InnerHandler?是?DelegatingHandler2,以此類推,在?DelegatingHandler3?的?InnerHandler?處理請(qǐng)求的時(shí)候就轉(zhuǎn)發(fā)到了相關(guān)控制器,這里和 .net?core?中的中間件非常相似,在.net?core 中間件順序是?RequestServicesContainerMiddleware(給請(qǐng)求上下文綁定容器)->?AuthenticationMiddleware(認(rèn)證)-> RouterMiddleware (路由以及MVC)
如果我們?cè)?ValuesController?中觀察表達(dá)式?this.RequestContext.Configuration.MessageHandlers?還可以看到最終處理請(qǐng)求的是一個(gè)?HttpRoutingDispatcher,最也是是分配到路由以及控制器來(lái)處理的,按照如此方式我們可以很容易在?asp.net?web api?中對(duì)請(qǐng)求統(tǒng)計(jì)。這里是比較簡(jiǎn)陋的,對(duì)此我們可以記錄客戶端和服務(wù)器更詳細(xì)的信息,包括?IP?地址,http狀態(tài)碼,是否是認(rèn)證用戶等等,但是這篇主要是以?asp.net?core?為主的,所以這里就不詳細(xì)寫(xiě)下去了。
?二:asp.net?core?中間件 + NLog 實(shí)現(xiàn)請(qǐng)求監(jiān)控
?先看統(tǒng)計(jì)結(jié)果,start?開(kāi)始時(shí)間,time?是請(qǐng)求消耗時(shí)間(毫秒),authenicate?是認(rèn)證通過(guò)的?schema,使用 NLog?自定義字段也是非常方便的
先說(shuō)一說(shuō)遇到的問(wèn)題
(1)NLog?記錄一張以上的表如何實(shí)現(xiàn),應(yīng)為首先會(huì)有一個(gè)一般性的日志表(稱他為?log),并且這些統(tǒng)計(jì)不對(duì)寫(xiě)到?log?表
(2)使用?NLog?自定義字段?LayoutRenderer?沒(méi)有類似 .net framework?中的?System.Web.Current
(3)使用?UseMiddleware?無(wú)法在讓我們的中間件成為第一個(gè)中間件
(4)實(shí)現(xiàn)忽略記錄的方法,肯定有一些接口是不希望記錄的,所以這個(gè)也要實(shí)現(xiàn)
?NLog?配置
這里只列出了部分內(nèi)容,github 地址在最后,數(shù)據(jù)庫(kù)是?mysql ,apiinsight?表示請(qǐng)求統(tǒng)計(jì),log?是一般性的日志,debughelper?可以加快我們調(diào)試時(shí)日志的檢索速度
在?Startup?中
自定義字段都是通過(guò)?LayoutRenderer?實(shí)現(xiàn),由于自定義字段有很多,這里只列出了一個(gè)開(kāi)始時(shí)間是如何查詢的,這個(gè)時(shí)間是在我們注冊(cè)的第一個(gè)中間件執(zhí)行 Invoke?方法的時(shí)候?qū)戇M(jìn)?HttpContext.Items?的
?NLog 規(guī)則,很容易理解日志統(tǒng)計(jì)只記錄?Cheers?命名空間下的日志
?核心 ApiInsightMiddleware?中間件
很好理解,在執(zhí)行下一個(gè)中間件之前調(diào)用?SetValues?開(kāi)始計(jì)時(shí),下一個(gè)中間件執(zhí)行成功開(kāi)始統(tǒng)計(jì)并寫(xiě)入日志(或者忽略不寫(xiě))。現(xiàn)在他是?asp.net core?mvc?的第一個(gè)中間件了,好處就是更符合這個(gè)中間件本身的所做的事情了,但是帶來(lái)的問(wèn)題就是?httpContext.RequestService?是 null ,因?yàn)?RequestService?是在?RequestServicesContainerMiddleware?這個(gè)中間件寫(xiě)進(jìn)去的,在者其實(shí)很多地方我們都需要?HttpContext ,并且目前微軟還沒(méi)有給我們定義一個(gè)靜態(tài)的?HttpContext。
靜態(tài)的?HttpContext
HttpContext?是通過(guò)單例 IHttpContextAccessor?提供的,當(dāng)?HttpContext?創(chuàng)建的時(shí)候就會(huì)賦值給他,當(dāng)請(qǐng)求到達(dá)中間件這個(gè)管道的時(shí)候,HttpContext?就已經(jīng)存在于?IHttpContextAccessor?了,并且和?Invoke?參數(shù)列表中的?HttpContext?是一致的(同一個(gè)請(qǐng)求中),問(wèn)題在于?RequestServicesContainerMiddleware?這個(gè)中間件沒(méi)有執(zhí)行就沒(méi)有容器,并且很多時(shí)候我們都要用到容器,所以就模仿源碼在這里都加進(jìn)去了。
我們只需要在?Startup?中使用?app.UseGlobalHttpContext();?就可以在程序的任何地方得到?HttpContext?和容器了,肯定會(huì)有人說(shuō)為什么不通過(guò)構(gòu)造函數(shù)來(lái)獲取我們想要的注入呢,因?yàn)橛行┑谌娇蚣芑蜻@某些地方我們不能使用容器獲取服務(wù),比如這里 NLog?的自定義字段使用的?LayoutRenderer?就無(wú)法通過(guò)構(gòu)造器得到我們想要的服務(wù)。
第一個(gè)中間件
在?Startup?的?Configure?方法中目前還沒(méi)發(fā)現(xiàn)如何注冊(cè)第一個(gè)中間件,因?yàn)?Configure?方法始終是在?IStartupFilter?這個(gè)接口之后執(zhí)行的,這也提供了我們讓自己的中間件成為第一個(gè)中間件的可能??赡苓@樣做并不是特別有必要,甚至是沒(méi)有意義的,但是實(shí)現(xiàn)的過(guò)程確實(shí)很有意思的。這里在?Startup?中的?方法?ConfigureService 注冊(cè)我們的中間件。
具體的
這里注冊(cè)了三個(gè)服務(wù)
IApiInsightsKeys
定義了存儲(chǔ)在?HttpContext.Item?中的鍵值對(duì)的名稱
IRequestIsAuthenticate
就驗(yàn)證而言可能不同的開(kāi)發(fā)者使用的是不一樣的驗(yàn)證方式,可能是基于 Asp.Net Core?Authentication?中間件的認(rèn)證方式,也可能是其他的比如自定義的?token,或者有一個(gè)單點(diǎn)登錄的服務(wù)器,又或者是?session,其實(shí) Asp.Net Core?的?Authentication?中間件也可以幫我們實(shí)現(xiàn)基于?restful?的token?認(rèn)證。所以就把它定義出來(lái)了,并且默認(rèn)的實(shí)現(xiàn)就是基于?Authentication?這個(gè)中間件的。
IStartupFilter
看到他是一個(gè)非常特殊的方式來(lái)注冊(cè)的,自定義的 FirstRegister?這個(gè)方法,實(shí)際上?Asp.Net?Core?內(nèi)置有多個(gè)?IStartup?這樣的服務(wù),并且都是在?Startup?的?Configure?之前執(zhí)行的,所以這里一定要用這個(gè)服務(wù)來(lái)讓我們的中間件成為第一個(gè)中間件。FirstRegister?代碼也很容易理解,由于在宿主啟動(dòng)之前,內(nèi)部注冊(cè)了多個(gè)?IStartup,并且最后會(huì)按先后順序配置 IApplicationBuilder,所以我們只能讓第一個(gè) StartupFilter 的?IApplicationBuilder 就注冊(cè)我們的中間件,通過(guò)改動(dòng) ServiceCollection 中服務(wù)的順序可以實(shí)現(xiàn)。雖然不是很有必要,但是可以從中觀察的 Startup 的 Configure方法 以及 接口StartupFilter (還有 IHostingStartup )的執(zhí)行順序。
忽略的方法
在 ApiInsight 方法中會(huì)調(diào)用 IsIgnore 檢測(cè)該方法是否打了標(biāo)簽?NoInsightAttribute,如果是那就忽略該方法,這里建議使用特性路由,原因有兩點(diǎn),第一特性路由不需要使用?IActionSelector 接口重新查找匹配的方法,第二,在 restful api 中,結(jié)合特性路由和 HttpMethodAttribute 標(biāo)簽可以使方法更簡(jiǎn)潔,相同的接口名稱通過(guò)不同的請(qǐng)求方式達(dá)到不同的目的
好看你就點(diǎn)點(diǎn)我看完本文有收獲?請(qǐng)轉(zhuǎn)發(fā)分享給更多人
關(guān)注「.net學(xué)院」,提升.Net技能?
總結(jié)
以上是生活随笔為你收集整理的invoke方法是做啥的_使用 NLog 给 Asp.Net Core 做请求监控的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 基于java的数据结构学习——泛型动态数
- 下一篇: exgcd模板