ASP.NET Core如何在ActionFilterAttribute裏作依賴注入

文章來源:http://www.dalbll.com/group/topic/asp.net/6333面試

在ASP.NET Core裏,咱們可使用構造函數注入很方便地對Controller,ViewComponent等部件作依賴注入。可是如何給過濾器ActionFilterAttribute也用上構造函數注入呢?緩存

問題
個人博客系統裏有個用來刪除訂閱文件緩存的ActionFilter,想要在發生異常的時候記錄日誌。個人博客用的日誌組件是NLog,所以不使用依賴注入的話,就直接使用LogManager.GetCurrentClassLogger()得到一個Logger的實例。整個過濾器的代碼以下:asp.net

 1 public class DeleteSubscriptionCache : ActionFilterAttribute
 2 {
 3     private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
 4 
 5     public override void OnActionExecuted(ActionExecutedContext context)
 6     {
 7         base.OnActionExecuted(context);
 8         DeleteSubscriptionFiles();
 9     }
10 
11     private void DeleteSubscriptionFiles()
12     {
13         try
14         {
15             // ...
16         }
17         catch (Exception e)
18         {
19             Logger.Error(e, "Error Delete Subscription Files");
20         }
21     }
22 }

而後在Action上去使用,和經典的ASP.NET MVC同樣ide

1 [Authorize]
2 [HttpPost, ValidateAntiForgeryToken, DeleteSubscriptionCache]
3 [Route("manage/edit")]
4 public IActionResult Edit(PostEditModel model)

這固然能夠沒有問題的運行,但寫代碼最重要的就是逼格,這個代碼耦合了NLog,而個人博客系統裏其餘地方早就在用ASP.NET Core的ILogger接口了。若是哪天日誌組件再也不用NLog了,那麼這個地方的代碼就得改,而使用ILogger接口的代碼就不須要動。雖然這種狀況是絕對不會發生的,可是寫代碼必定要有追求,儘量過分設計,才能不被人鄙視,而後才能面試造航母,工做擰螺絲。所以我決定把日誌組件用依賴注入的方式安排一下。函數

改造過濾器
方法和在Controller中使用依賴注入徹底同樣,咱們使用構造函數注入ILogger<DeleteSubscriptionCache>類型。因而代碼變成了這樣:spa

 1 public class DeleteSubscriptionCache : ActionFilterAttribute
 2 {
 3     protected readonly ILogger<DeleteSubscriptionCache> Logger;
 4 
 5     public DeleteSubscriptionCache(ILogger<DeleteSubscriptionCache> logger)
 6     {
 7         Logger = logger;
 8     }
 9 
10     public override void OnActionExecuted(ActionExecutedContext context)
11     {
12         base.OnActionExecuted(context);
13         DeleteSubscriptionFiles();
14     }
15 
16     private void DeleteSubscriptionFiles()
17     {
18         try
19         {
20             // ...
21         }
22         catch (Exception e)
23         {
24             Logger.LogError(e, "Error Delete Subscription Files");
25         }
26     }
27 }

可是問題來了,這樣的話咱們是無法在Action上無腦使用了,由於構造函數要求傳參。若是要本身new一個的話,裝逼就失敗了。咱們來看看正確的解決方法~.net

 

ServiceFilter
其實ASP.NET Core裏,咱們可使用ServiceFilter來完成這個需求。它也是一種Attribute,能夠做用在Action上。位於Microsoft.AspNetCore.Mvc.Core程序集裏,定義以下:設計

 1 // A filter that finds another filter in an System.IServiceProvider.
 2 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
 3 public class ServiceFilterAttribute : Attribute, IFilterFactory, IFilterMetadata, IOrderedFilter
 4 {
 5         public ServiceFilterAttribute(Type type);
 6         public int Order { get; set; }
 7         public Type ServiceType { get; }
 8         public bool IsReusable { get; set; }
 9         public IFilterMetadata CreateInstance(IServiceProvider serviceProvider);
10 }

ServiceFilter容許咱們解析一個已經添加到IoC容器裏的服務,所以咱們須要把DeleteSubscriptionCache註冊一下:
services.AddScoped<DeleteSubscriptionCache>();
而後就能直接使用了:日誌

1 [Authorize]
2 [HttpPost, ValidateAntiForgeryToken]
3 [ServiceFilter(typeof(DeleteSubscriptionCache))]
4 [Route("manage/edit")]
5 public IActionResult Edit(PostEditModel model)

 

運行時發現ILogger已經能被實例化了,完美!code

 

相關文章
相關標籤/搜索