ASP.NET Core如何在ActionFilterAttribute里做依赖注入
點擊藍(lán)字
關(guān)注我
在ASP.NET Core里,我們可以使用構(gòu)造函數(shù)注入很方便地對Controller,ViewComponent等部件做依賴注入。但是如何給過濾器ActionFilterAttribute也用上構(gòu)造函數(shù)注入呢?
問題
我的博客系統(tǒng)里有個用來刪除訂閱文件緩存的ActionFilter,想要在發(fā)生異常的時候記錄日志。我的博客用的日志組件是NLog,因此不使用依賴注入的話,就直接使用LogManager.GetCurrentClassLogger()獲得一個Logger的實例。整個過濾器的代碼如下:
public class DeleteSubscriptionCache : ActionFilterAttribute
{
? ? private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
? ? public override void OnActionExecuted(ActionExecutedContext context)
? ? {
? ? ? ? base.OnActionExecuted(context);
? ? ? ? DeleteSubscriptionFiles();
? ? }
? ? private void DeleteSubscriptionFiles()
? ? {
? ? ? ? try
? ? ? ? {
? ? ? ? ? ? // ...
? ? ? ? }
? ? ? ? catch (Exception e)
? ? ? ? {
? ? ? ? ? ? Logger.Error(e, "Error Delete Subscription Files");
? ? ? ? }
? ? }
}
然后在Action上去使用,和經(jīng)典的ASP.NET MVC一樣
[Authorize]
[HttpPost, ValidateAntiForgeryToken, DeleteSubscriptionCache]
[Route("manage/edit")]
public IActionResult Edit(PostEditModel model)
這當(dāng)然可以沒有問題的運行,但寫代碼最重要的就是逼格,這個代碼耦合了NLog,而我的博客系統(tǒng)里其他地方早就在用ASP.NET Core的ILogger接口了。如果哪天日志組件不再用NLog了,那么這個地方的代碼就得改,而使用ILogger接口的代碼就不需要動。雖然這種情況是絕對不會發(fā)生的,但是寫代碼一定要有追求,盡可能過度設(shè)計,才能不被人鄙視,然后才能面試造航母,工作擰螺絲。因此我決定把日志組件用依賴注入的方式安排一下。
改造過濾器
方法和在Controller中使用依賴注入完全一樣,我們使用構(gòu)造函數(shù)注入ILogger<DeleteSubscriptionCache>類型。于是代碼變成了這樣:
public class DeleteSubscriptionCache : ActionFilterAttribute
{
? ? protected readonly ILogger<DeleteSubscriptionCache> Logger;
? ? public DeleteSubscriptionCache(ILogger<DeleteSubscriptionCache> logger)
? ? {
? ? ? ? Logger = logger;
? ? }
? ? public override void OnActionExecuted(ActionExecutedContext context)
? ? {
? ? ? ? base.OnActionExecuted(context);
? ? ? ? DeleteSubscriptionFiles();
? ? }
? ? private void DeleteSubscriptionFiles()
? ? {
? ? ? ? try
? ? ? ? {
? ? ? ? ? ? // ...
? ? ? ? }
? ? ? ? catch (Exception e)
? ? ? ? {
? ? ? ? ? ? Logger.LogError(e, "Error Delete Subscription Files");
? ? ? ? }
? ? }
}
但是問題來了,這樣的話我們是沒法在Action上無腦使用了,因為構(gòu)造函數(shù)要求傳參。如果要自己new一個的話,裝逼就失敗了。我們來看看正確的解決方法~
ServiceFilter
其實ASP.NET Core里,我們可以使用ServiceFilter來完成這個需求。它也是一種Attribute,可以作用在Action上。位于Microsoft.AspNetCore.Mvc.Core程序集里,定義如下:
// A filter that finds another filter in an System.IServiceProvider.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class ServiceFilterAttribute : Attribute, IFilterFactory, IFilterMetadata, IOrderedFilter
{
? ? ? ? public ServiceFilterAttribute(Type type);
? ? ? ? public int Order { get; set; }
? ? ? ? public Type ServiceType { get; }
? ? ? ? public bool IsReusable { get; set; }
? ? ? ? public IFilterMetadata CreateInstance(IServiceProvider serviceProvider);
}
ServiceFilter允許我們解析一個已經(jīng)添加到IoC容器里的服務(wù),因此我們需要把DeleteSubscriptionCache注冊一下:
services.AddScoped<DeleteSubscriptionCache>();
然后就能直接使用了:
[Authorize]
[HttpPost, ValidateAntiForgeryToken]
[ServiceFilter(typeof(DeleteSubscriptionCache))]
[Route("manage/edit")]
public IActionResult Edit(PostEditModel model)
運行時發(fā)現(xiàn)ILogger已經(jīng)能被實例化了,完美!
參考資料:
https://stackoverflow.com/questions/36109052/inject-service-into-action-filter/36109690
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core如何在ActionFilterAttribute里做依赖注入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新数据革命:开源图形化数据引擎Hawk5
- 下一篇: 助力苏州、星火相传,广苏两地微软技术俱乐