1. title: Asp.Net Core底层源码剖析(二)过滤器
  2. date: 2022-09-18 10:41:57
  3. categories: 后端
  4. tags:
  5. - .NET

正文

Asp.Net Core中的过滤器有好几种,包括AuthorizationFilter、ActionFilter,ResourceFilter,ExceptionFilter,ResultFilter,平时一般用的多的就是AuthorizationFilter、ActionFilter、ExceptionFilter三个,下面我们写个自定义的ActionFilter,然后debug看一下源码

自定义ActionFilter

我们自定义的ActionFilter可以继承自ActionFilterAttribute,也可以直接实现接口IActionFilter,两者的作用是差不多的,因为ActionFilterAttribute也实现了这个接口,我们看下源码:

  1. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
  2. public abstract class ActionFilterAttribute :
  3. Attribute, IActionFilter, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter
  4. {
  5. // 实现...
  6. }

可以看出,ActionFilterAttribute继承了好几个接口,下面是这几个接口的简单说明

所以我们直接继承ActionFilterAttribute,其实同时实现了好几个方法:

  1. public class MyActionFilterAttribute:ActionFilterAttribute
  2. {
  3. public override void OnActionExecuting(ActionExecutingContext actionExecutingContext)
  4. {
  5. Console.WriteLine("OnActionExecuting");
  6. }
  7. public override void OnActionExecuted(ActionExecutedContext context)
  8. {
  9. base.OnActionExecuted(context);
  10. Console.WriteLine("OnActionExecuted");
  11. }
  12. public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  13. {
  14. return base.OnActionExecutionAsync(context, next);
  15. Console.WriteLine("OnActionExecutionAsync");
  16. }
  17. public override void OnResultExecuting(ResultExecutingContext context)
  18. {
  19. base.OnResultExecuting(context);
  20. Console.WriteLine("OnResultExecuting");
  21. }
  22. public override void OnResultExecuted(ResultExecutedContext context)
  23. {
  24. base.OnResultExecuted(context);
  25. Console.WriteLine("OnResultExecuted");
  26. }
  27. public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
  28. {
  29. return base.OnResultExecutionAsync(context, next);
  30. Console.WriteLine("OnResultExecuted");
  31. }
  32. }

下面我们把自己写的过滤器添加到全局的过滤器中,而不是直接用在controller或者方法上

  1. builder.Services.AddMvc(it => it.Filters.Add(typeof(MyActionFilterAttribute)));

然后我们开始debug,给OnActionExecuting函数打个断点,然后查看运行的堆栈,我们可以看到是在EndpointMiddleware中间件内部来调用过滤器的

接着我们继续往下,能找到下面这个函数

  1. private Task Next(ref State next, ref Scope scope, ref object? state, ref bool isCompleted)
  2. {
  3. switch (next)
  4. {
  5. case State.InvokeBegin:
  6. {
  7. goto case State.AuthorizationBegin;
  8. }
  9. case State.AuthorizationBegin:
  10. {
  11. _cursor.Reset();
  12. goto case State.AuthorizationNext;
  13. }
  14. case State.AuthorizationNext:
  15. {
  16. var current = _cursor.GetNextFilter<IAuthorizationFilter, IAsyncAuthorizationFilter>();
  17. if (current.FilterAsync != null)
  18. {
  19. if (_authorizationContext == null)
  20. {
  21. _authorizationContext = new AuthorizationFilterContextSealed(_actionContext, _filters);
  22. }
  23. state = current.FilterAsync;
  24. goto case State.AuthorizationAsyncBegin;
  25. }
  26. else if (current.Filter != null)
  27. {
  28. if (_authorizationContext == null)
  29. {
  30. _authorizationContext = new AuthorizationFilterContextSealed(_actionContext, _filters);
  31. }
  32. state = current.Filter;
  33. goto case State.AuthorizationSync;
  34. }
  35. else
  36. {
  37. goto case State.AuthorizationEnd;
  38. }
  39. }
  40. case State.AuthorizationAsyncBegin:
  41. {
  42. Debug.Assert(state != null);
  43. Debug.Assert(_authorizationContext != null);
  44. var filter = (IAsyncAuthorizationFilter)state;
  45. var authorizationContext = _authorizationContext;
  46. _diagnosticListener.BeforeOnAuthorizationAsync(authorizationContext, filter);
  47. _logger.BeforeExecutingMethodOnFilter(
  48. FilterTypeConstants.AuthorizationFilter,
  49. nameof(IAsyncAuthorizationFilter.OnAuthorizationAsync),
  50. filter);
  51. var task = filter.OnAuthorizationAsync(authorizationContext);
  52. if (!task.IsCompletedSuccessfully)
  53. {
  54. next = State.AuthorizationAsyncEnd;
  55. return task;
  56. }
  57. goto case State.AuthorizationAsyncEnd;
  58. }
  59. case State.AuthorizationAsyncEnd:
  60. {
  61. Debug.Assert(state != null);
  62. Debug.Assert(_authorizationContext != null);
  63. var filter = (IAsyncAuthorizationFilter)state;
  64. var authorizationContext = _authorizationContext;
  65. _diagnosticListener.AfterOnAuthorizationAsync(authorizationContext, filter);
  66. _logger.AfterExecutingMethodOnFilter(
  67. FilterTypeConstants.AuthorizationFilter,
  68. nameof(IAsyncAuthorizationFilter.OnAuthorizationAsync),
  69. filter);
  70. if (authorizationContext.Result != null)
  71. {
  72. goto case State.AuthorizationShortCircuit;
  73. }
  74. goto case State.AuthorizationNext;
  75. }
  76. case State.AuthorizationSync:
  77. {
  78. Debug.Assert(state != null);
  79. Debug.Assert(_authorizationContext != null);
  80. var filter = (IAuthorizationFilter)state;
  81. var authorizationContext = _authorizationContext;
  82. _diagnosticListener.BeforeOnAuthorization(authorizationContext, filter);
  83. _logger.BeforeExecutingMethodOnFilter(
  84. FilterTypeConstants.AuthorizationFilter,
  85. nameof(IAuthorizationFilter.OnAuthorization),
  86. filter);
  87. filter.OnAuthorization(authorizationContext);
  88. _diagnosticListener.AfterOnAuthorization(authorizationContext, filter);
  89. _logger.AfterExecutingMethodOnFilter(
  90. FilterTypeConstants.AuthorizationFilter,
  91. nameof(IAuthorizationFilter.OnAuthorization),
  92. filter);
  93. if (authorizationContext.Result != null)
  94. {
  95. goto case State.AuthorizationShortCircuit;
  96. }
  97. goto case State.AuthorizationNext;
  98. }
  99. case State.AuthorizationShortCircuit:
  100. {
  101. Debug.Assert(state != null);
  102. Debug.Assert(_authorizationContext != null);
  103. Debug.Assert(_authorizationContext.Result != null);
  104. _logger.AuthorizationFailure((IFilterMetadata)state);
  105. // This is a short-circuit - execute relevant result filters + result and complete this invocation.
  106. isCompleted = true;
  107. _result = _authorizationContext.Result;
  108. return InvokeAlwaysRunResultFilters();
  109. }
  110. case State.AuthorizationEnd:
  111. {
  112. goto case State.ResourceBegin;
  113. }
  114. case State.ResourceBegin:
  115. {
  116. _cursor.Reset();
  117. goto case State.ResourceNext;
  118. }
  119. case State.ResourceNext:
  120. {
  121. var current = _cursor.GetNextFilter<IResourceFilter, IAsyncResourceFilter>();
  122. if (current.FilterAsync != null)
  123. {
  124. if (_resourceExecutingContext == null)
  125. {
  126. _resourceExecutingContext = new ResourceExecutingContextSealed(
  127. _actionContext,
  128. _filters,
  129. _valueProviderFactories);
  130. }
  131. state = current.FilterAsync;
  132. goto case State.ResourceAsyncBegin;
  133. }
  134. else if (current.Filter != null)
  135. {
  136. if (_resourceExecutingContext == null)
  137. {
  138. _resourceExecutingContext = new ResourceExecutingContextSealed(
  139. _actionContext,
  140. _filters,
  141. _valueProviderFactories);
  142. }
  143. state = current.Filter;
  144. goto case State.ResourceSyncBegin;
  145. }
  146. else
  147. {
  148. // All resource filters are currently on the stack - now execute the 'inside'.
  149. goto case State.ResourceInside;
  150. }
  151. }
  152. case State.ResourceAsyncBegin:
  153. {
  154. Debug.Assert(state != null);
  155. Debug.Assert(_resourceExecutingContext != null);
  156. var filter = (IAsyncResourceFilter)state;
  157. var resourceExecutingContext = _resourceExecutingContext;
  158. _diagnosticListener.BeforeOnResourceExecution(resourceExecutingContext, filter);
  159. _logger.BeforeExecutingMethodOnFilter(
  160. FilterTypeConstants.ResourceFilter,
  161. nameof(IAsyncResourceFilter.OnResourceExecutionAsync),
  162. filter);
  163. var task = filter.OnResourceExecutionAsync(resourceExecutingContext, InvokeNextResourceFilterAwaitedAsync);
  164. if (!task.IsCompletedSuccessfully)
  165. {
  166. next = State.ResourceAsyncEnd;
  167. return task;
  168. }
  169. goto case State.ResourceAsyncEnd;
  170. }
  171. case State.ResourceAsyncEnd:
  172. {
  173. Debug.Assert(state != null);
  174. Debug.Assert(_resourceExecutingContext != null);
  175. var filter = (IAsyncResourceFilter)state;
  176. if (_resourceExecutedContext == null)
  177. {
  178. // If we get here then the filter didn't call 'next' indicating a short circuit.
  179. _resourceExecutedContext = new ResourceExecutedContextSealed(_resourceExecutingContext, _filters)
  180. {
  181. Canceled = true,
  182. Result = _resourceExecutingContext.Result,
  183. };
  184. _diagnosticListener.AfterOnResourceExecution(_resourceExecutedContext, filter);
  185. _logger.AfterExecutingMethodOnFilter(
  186. FilterTypeConstants.ResourceFilter,
  187. nameof(IAsyncResourceFilter.OnResourceExecutionAsync),
  188. filter);
  189. // A filter could complete a Task without setting a result
  190. if (_resourceExecutingContext.Result != null)
  191. {
  192. goto case State.ResourceShortCircuit;
  193. }
  194. }
  195. goto case State.ResourceEnd;
  196. }
  197. case State.ResourceSyncBegin:
  198. {
  199. Debug.Assert(state != null);
  200. Debug.Assert(_resourceExecutingContext != null);
  201. var filter = (IResourceFilter)state;
  202. var resourceExecutingContext = _resourceExecutingContext;
  203. _diagnosticListener.BeforeOnResourceExecuting(resourceExecutingContext, filter);
  204. _logger.BeforeExecutingMethodOnFilter(
  205. FilterTypeConstants.ResourceFilter,
  206. nameof(IResourceFilter.OnResourceExecuting),
  207. filter);
  208. filter.OnResourceExecuting(resourceExecutingContext);
  209. _diagnosticListener.AfterOnResourceExecuting(resourceExecutingContext, filter);
  210. _logger.AfterExecutingMethodOnFilter(
  211. FilterTypeConstants.ResourceFilter,
  212. nameof(IResourceFilter.OnResourceExecuting),
  213. filter);
  214. if (resourceExecutingContext.Result != null)
  215. {
  216. _resourceExecutedContext = new ResourceExecutedContextSealed(resourceExecutingContext, _filters)
  217. {
  218. Canceled = true,
  219. Result = _resourceExecutingContext.Result,
  220. };
  221. goto case State.ResourceShortCircuit;
  222. }
  223. var task = InvokeNextResourceFilter();
  224. if (!task.IsCompletedSuccessfully)
  225. {
  226. next = State.ResourceSyncEnd;
  227. return task;
  228. }
  229. goto case State.ResourceSyncEnd;
  230. }
  231. case State.ResourceSyncEnd:
  232. {
  233. Debug.Assert(state != null);
  234. Debug.Assert(_resourceExecutingContext != null);
  235. Debug.Assert(_resourceExecutedContext != null);
  236. var filter = (IResourceFilter)state;
  237. var resourceExecutedContext = _resourceExecutedContext;
  238. _diagnosticListener.BeforeOnResourceExecuted(resourceExecutedContext, filter);
  239. _logger.BeforeExecutingMethodOnFilter(
  240. FilterTypeConstants.ResourceFilter,
  241. nameof(IResourceFilter.OnResourceExecuted),
  242. filter);
  243. filter.OnResourceExecuted(resourceExecutedContext);
  244. _diagnosticListener.AfterOnResourceExecuted(resourceExecutedContext, filter);
  245. _logger.AfterExecutingMethodOnFilter(
  246. FilterTypeConstants.ResourceFilter,
  247. nameof(IResourceFilter.OnResourceExecuted),
  248. filter);
  249. goto case State.ResourceEnd;
  250. }
  251. case State.ResourceShortCircuit:
  252. {
  253. Debug.Assert(state != null);
  254. Debug.Assert(_resourceExecutingContext != null);
  255. Debug.Assert(_resourceExecutedContext != null);
  256. _logger.ResourceFilterShortCircuited((IFilterMetadata)state);
  257. _result = _resourceExecutingContext.Result;
  258. var task = InvokeAlwaysRunResultFilters();
  259. if (!task.IsCompletedSuccessfully)
  260. {
  261. next = State.ResourceEnd;
  262. return task;
  263. }
  264. goto case State.ResourceEnd;
  265. }
  266. case State.ResourceInside:
  267. {
  268. goto case State.ExceptionBegin;
  269. }
  270. case State.ExceptionBegin:
  271. {
  272. _cursor.Reset();
  273. goto case State.ExceptionNext;
  274. }
  275. case State.ExceptionNext:
  276. {
  277. var current = _cursor.GetNextFilter<IExceptionFilter, IAsyncExceptionFilter>();
  278. if (current.FilterAsync != null)
  279. {
  280. state = current.FilterAsync;
  281. goto case State.ExceptionAsyncBegin;
  282. }
  283. else if (current.Filter != null)
  284. {
  285. state = current.Filter;
  286. goto case State.ExceptionSyncBegin;
  287. }
  288. else if (scope == Scope.Exception)
  289. {
  290. // All exception filters are on the stack already - so execute the 'inside'.
  291. goto case State.ExceptionInside;
  292. }
  293. else
  294. {
  295. // There are no exception filters - so jump right to the action.
  296. Debug.Assert(scope == Scope.Invoker || scope == Scope.Resource);
  297. goto case State.ActionBegin;
  298. }
  299. }
  300. case State.ExceptionAsyncBegin:
  301. {
  302. var task = InvokeNextExceptionFilterAsync();
  303. if (!task.IsCompletedSuccessfully)
  304. {
  305. next = State.ExceptionAsyncResume;
  306. return task;
  307. }
  308. goto case State.ExceptionAsyncResume;
  309. }
  310. case State.ExceptionAsyncResume:
  311. {
  312. Debug.Assert(state != null);
  313. var filter = (IAsyncExceptionFilter)state;
  314. var exceptionContext = _exceptionContext;
  315. // When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception,
  316. // we'll call the filter. Otherwise there's nothing to do.
  317. if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled)
  318. {
  319. _diagnosticListener.BeforeOnExceptionAsync(exceptionContext, filter);
  320. _logger.BeforeExecutingMethodOnFilter(
  321. FilterTypeConstants.ExceptionFilter,
  322. nameof(IAsyncExceptionFilter.OnExceptionAsync),
  323. filter);
  324. var task = filter.OnExceptionAsync(exceptionContext);
  325. if (!task.IsCompletedSuccessfully)
  326. {
  327. next = State.ExceptionAsyncEnd;
  328. return task;
  329. }
  330. goto case State.ExceptionAsyncEnd;
  331. }
  332. goto case State.ExceptionEnd;
  333. }
  334. case State.ExceptionAsyncEnd:
  335. {
  336. Debug.Assert(state != null);
  337. Debug.Assert(_exceptionContext != null);
  338. var filter = (IAsyncExceptionFilter)state;
  339. var exceptionContext = _exceptionContext;
  340. _diagnosticListener.AfterOnExceptionAsync(exceptionContext, filter);
  341. _logger.AfterExecutingMethodOnFilter(
  342. FilterTypeConstants.ExceptionFilter,
  343. nameof(IAsyncExceptionFilter.OnExceptionAsync),
  344. filter);
  345. if (exceptionContext.Exception == null || exceptionContext.ExceptionHandled)
  346. {
  347. // We don't need to do anything to trigger a short circuit. If there's another
  348. // exception filter on the stack it will check the same set of conditions
  349. // and then just skip itself.
  350. _logger.ExceptionFilterShortCircuited(filter);
  351. }
  352. goto case State.ExceptionEnd;
  353. }
  354. case State.ExceptionSyncBegin:
  355. {
  356. var task = InvokeNextExceptionFilterAsync();
  357. if (!task.IsCompletedSuccessfully)
  358. {
  359. next = State.ExceptionSyncEnd;
  360. return task;
  361. }
  362. goto case State.ExceptionSyncEnd;
  363. }
  364. case State.ExceptionSyncEnd:
  365. {
  366. Debug.Assert(state != null);
  367. var filter = (IExceptionFilter)state;
  368. var exceptionContext = _exceptionContext;
  369. // When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception,
  370. // we'll call the filter. Otherwise there's nothing to do.
  371. if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled)
  372. {
  373. _diagnosticListener.BeforeOnException(exceptionContext, filter);
  374. _logger.BeforeExecutingMethodOnFilter(
  375. FilterTypeConstants.ExceptionFilter,
  376. nameof(IExceptionFilter.OnException),
  377. filter);
  378. filter.OnException(exceptionContext);
  379. _diagnosticListener.AfterOnException(exceptionContext, filter);
  380. _logger.AfterExecutingMethodOnFilter(
  381. FilterTypeConstants.ExceptionFilter,
  382. nameof(IExceptionFilter.OnException),
  383. filter);
  384. if (exceptionContext.Exception == null || exceptionContext.ExceptionHandled)
  385. {
  386. // We don't need to do anything to trigger a short circuit. If there's another
  387. // exception filter on the stack it will check the same set of conditions
  388. // and then just skip itself.
  389. _logger.ExceptionFilterShortCircuited(filter);
  390. }
  391. }
  392. goto case State.ExceptionEnd;
  393. }
  394. case State.ExceptionInside:
  395. {
  396. goto case State.ActionBegin;
  397. }
  398. case State.ExceptionHandled:
  399. {
  400. // We arrive in this state when an exception happened, but was handled by exception filters
  401. // either by setting ExceptionHandled, or nulling out the Exception or setting a result
  402. // on the ExceptionContext.
  403. //
  404. // We need to execute the result (if any) and then exit gracefully which unwinding Resource
  405. // filters.
  406. Debug.Assert(state != null);
  407. Debug.Assert(_exceptionContext != null);
  408. if (_exceptionContext.Result == null)
  409. {
  410. _exceptionContext.Result = new EmptyResult();
  411. }
  412. _result = _exceptionContext.Result;
  413. var task = InvokeAlwaysRunResultFilters();
  414. if (!task.IsCompletedSuccessfully)
  415. {
  416. next = State.ResourceInsideEnd;
  417. return task;
  418. }
  419. goto case State.ResourceInsideEnd;
  420. }
  421. case State.ExceptionEnd:
  422. {
  423. var exceptionContext = _exceptionContext;
  424. if (scope == Scope.Exception)
  425. {
  426. isCompleted = true;
  427. return Task.CompletedTask;
  428. }
  429. if (exceptionContext != null)
  430. {
  431. if (exceptionContext.Result != null ||
  432. exceptionContext.Exception == null ||
  433. exceptionContext.ExceptionHandled)
  434. {
  435. goto case State.ExceptionHandled;
  436. }
  437. Rethrow(exceptionContext);
  438. Debug.Fail("unreachable");
  439. }
  440. var task = InvokeResultFilters();
  441. if (!task.IsCompletedSuccessfully)
  442. {
  443. next = State.ResourceInsideEnd;
  444. return task;
  445. }
  446. goto case State.ResourceInsideEnd;
  447. }
  448. case State.ActionBegin:
  449. {
  450. var task = InvokeInnerFilterAsync();
  451. if (!task.IsCompletedSuccessfully)
  452. {
  453. next = State.ActionEnd;
  454. return task;
  455. }
  456. goto case State.ActionEnd;
  457. }
  458. case State.ActionEnd:
  459. {
  460. if (scope == Scope.Exception)
  461. {
  462. // If we're inside an exception filter, let's allow those filters to 'unwind' before
  463. // the result.
  464. isCompleted = true;
  465. return Task.CompletedTask;
  466. }
  467. Debug.Assert(scope == Scope.Invoker || scope == Scope.Resource);
  468. var task = InvokeResultFilters();
  469. if (!task.IsCompletedSuccessfully)
  470. {
  471. next = State.ResourceInsideEnd;
  472. return task;
  473. }
  474. goto case State.ResourceInsideEnd;
  475. }
  476. case State.ResourceInsideEnd:
  477. {
  478. if (scope == Scope.Resource)
  479. {
  480. _resourceExecutedContext = new ResourceExecutedContextSealed(_actionContext, _filters)
  481. {
  482. Result = _result,
  483. };
  484. goto case State.ResourceEnd;
  485. }
  486. goto case State.InvokeEnd;
  487. }
  488. case State.ResourceEnd:
  489. {
  490. if (scope == Scope.Resource)
  491. {
  492. isCompleted = true;
  493. return Task.CompletedTask;
  494. }
  495. Debug.Assert(scope == Scope.Invoker);
  496. Rethrow(_resourceExecutedContext!);
  497. goto case State.InvokeEnd;
  498. }
  499. case State.InvokeEnd:
  500. {
  501. isCompleted = true;
  502. return Task.CompletedTask;
  503. }
  504. default:
  505. throw new InvalidOperationException();
  506. }
  507. }

上面这段就是过滤器的核心代码了,其实很简单,就是在一个switch里面不停地根据条件跳转,下面是官网上不同过滤器的执行顺序图

那么过滤器和管道之间的执行顺序又是什么样的呢?直接看官方文档内的图:

其实从刚开始的单步调试我们就已经知道了,是在EndpointMiddleware管道内执行的,也就是说先执行了一些我们自己添加的中间件,到最后和Action交互的时候才会执行相关的过滤器

过滤器和管道的重要区别

  1. 中间件可以处理所有的请求,而过滤器只能针对到达EndpointMiddleware Api的请求进行处理

  2. 过滤器处理的是ActionExecutingContextResultExecutedContext等,而中间件处理的是HttpContext,相较于HttpContextActionExecutingContext拥有了更多的信息,比如执行的方法,对应的参数等

以异常处理来举例,我们可以在中间件的级别来处理异常,也可以在过滤器的级别来处理异常,那一般情况下我们应该怎么选择呢?

  1. 如果我们需要处理Asp.Net Core框架内部的错误,比如管道中处理出现了一些异常,我们需要使用中间件处理异常,并且位于管道的开始位置
  2. 如果我们只关心自己的业务代码是否出现异常,比如controller中的action抛出了异常,我们可以使用过滤器,这样有个好处就是我们更方便获取对应抛出异常方法的信息
  3. 如果我们又想处理Asp.Net Core框架内部的异常,又想处理业务逻辑的异常,那么我们可以两者都同时使用

过滤器执行顺序

过滤器的执行是有顺序的,官方文档提供了一个表格我们可以参考一下:

Sequence Filter scope Filter method
1 Global OnActionExecuting
2 Controller OnActionExecuting
3 Action OnActionExecuting
4 Action OnActionExecuted
5 Controller OnActionExecuted
6 Global OnActionExecuted

看得出来顺序是这样的:

  1. 全局级别
  2. Controller级别
  3. Action级别

返回时执行顺序相反,这个顺序也不是写死的,我们可以通过配置一个字段来设置顺序:

  1. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
  2. public abstract class ActionFilterAttribute :
  3. Attribute, IActionFilter, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter
  4. {
  5. /// <inheritdoc />
  6. public int Order { get; set; }
  7. }

实现了IOrderedFilter接口的过滤器都可以通过Order字段设置执行顺序,这个Order的默认值都是0,我们可以在自定义的过滤器上添加下面的代码来测试是否是这样的:

  1. public int Level { get; set; } = 0;
  2. public override void OnActionExecuting(ActionExecutingContext actionExecutingContext)
  3. {
  4. Console.WriteLine($"OnActionExecuting {Order} {Level}");
  5. }

在全局、Controller和Action级别都添加一个:

  1. [MyActionFilter(Level = 100)]
  2. [Route("api/[controller]")]
  3. [ApiController]
  4. public class ValuesController : ControllerBase
  5. {
  6. public ValuesController()
  7. {
  8. }
  9. [MyActionFilter(Level = 99)]
  10. [HttpGet("test")]
  11. public string Test()
  12. {
  13. return "123";
  14. }
  15. }

最后调用这个接口,输出的结果为:

  1. OnActionExecuting 0 0
  2. OnActionExecuting 0 100
  3. OnActionExecuting 0 99

可以看出,默认的Order都是0,如果我们想要将某个过滤器在其它过滤器前执行,则可以手动设置Order的顺序,Order越小优先级越高

这里有个问题,如果我们设置某一个过滤器的执行顺序在全局和Controller之间,那我们也必须设置Controller级别的过滤器的Order属性,比如Action级别的过滤器Order为1,那么Controller级别的过滤器Orde必须大于1,如果涉及到很多个过滤器的话这里会比较复杂,而且不直观,所以一般情况下都不会对这个字段进行修改

参考

  1. https://stackoverflow.com/questions/42582758/asp-net-core-middleware-vs-filters

  2. https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0

  3. https://www.yogihosting.com/advanced-filters-topics-aspnet-core/#execution-order

  4. https://www.dotnettricks.com/learn/aspnetcore/mvc-core-filters-real-world-exmaple

  5. https://stackoverflow.com/questions/50887540/exceptionhandling-middleware-vs-filter-aspnetcore-webapi-2-1?noredirect=1&lq=1

  6. https://www.cnblogs.com/Bo-H/p/16584380.html

Asp-Net-Core-管道VS过滤器的更多相关文章

  1. ASP.NET CORE 管道模型及中间件使用解读

    说到ASP.NET CORE 管道模型不得不先来看看之前的ASP.NET 的管道模型,两者差异很大,.NET CORE 3.1 后完全重新设计了框架的底层,.net core 3.1 的管道模型更加灵 ...

  2. 通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程[下]:管道是如何构建起来的?

    在<中篇>中,我们对管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管道是如何被构建起来的.总的来说,管道由一个服务器和一个HttpApplication构成 ...

  3. ASP.NET Core管道深度剖析(4):管道是如何建立起来的?

    在<管道是如何处理HTTP请求的?>中,我们对ASP.NET Core的请求处理管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管道是如何被构建起来的.这样一 ...

  4. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  5. ASP.Net 管道模型 VS Asp.Net Core 管道 总结

    1 管道模型  1 Asp.Net Web Form管道 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象,封装此次请求有关的所有信息,然后进入HttpRuntime类进 ...

  6. ASP.NET Core管道深度剖析[共4篇]

    之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET Core应用的很多特性,比 ...

  7. ASP.NET Core管道深度剖析(3):管道是如何处理HTTP请求的?

    我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但是就具体的实现来说,由于其中涉及很多对象的交互,我想很少人能够地把它弄清楚.为了让读者 ...

  8. ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求

    之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET Core应用的很多特性,比 ...

  9. 【WPF】【UWP】借鉴 asp.net core 管道处理模型打造图片缓存控件 ImageEx

    在 Web 开发中,img 标签用来呈现图片,而且一般来说,浏览器是会对这些图片进行缓存的. 比如访问百度,我们可以发现,图片.脚本这种都是从缓存(内存缓存/磁盘缓存)中加载的,而不是再去访问一次百度 ...

  10. ASP.NET Core管道深度剖析

    ASP.NET管道 以IIS 6.0为例,在工作进程w3wp.exe中,利用Aspnet_ispai.dll加载.NET运行时(如果.NET运行时尚未加载).IIS 6引入了应用程序池的概念,一个工作 ...

随机推荐

  1. webscraper 无代码爬虫

    官网:https://www.webscraper.io/web-scraper-first-time-install webscraper 简介 Web Scraper 是一款免费的,适用于普通用户 ...

  2. VBA---文件操作

    Text文件操作 Workbooks.OpenText() 载入一个文本文档,并将其作为包含单个工作表的新工作簿进行分列处理. 语法: 表达式.OpenText(Filename,StartRow, ...

  3. chrome工具调试

    项目调试的困境 程序开发总会遇到各种各样的问题,为什么实际结果和预期结果不一致? 这个时候如果能深入程序内部抽丝剥茧去一探究竟再好不过! 而chrome工具是前端开发的杀手锏,经常听到的一句话是: 出 ...

  4. 试试将.NET7编译为WASM并在Docker上运行

    之前有听到说Docker支持Wasmtime了,刚好.NET7也支持WASM,就带大家来了解一下这个东西,顺便试试它怎么样. 因为WASM(WebAssembly) 一开始是一个给浏览器的技术,比起J ...

  5. CH58X/CH57X/V208 Observer(观察者)例程讨论讲解

    使用的是沁恒的CH582M的Observer例程与官方的demo板. 本例程的功能是主机扫描到从机的MAC地址并打印出来. 先对宏定义进行理解讨论. 最大响应扫描数为8,在串口调试助手那里可以看到打印 ...

  6. Java安全之CC4,5,7

    前言 前边已经将CC链中的关键部分学习差不多,接下来就是一些扩展思路, CC4 ObjectInputStream.readObject() PriorityQueue.readObject() Pr ...

  7. JavaScrip基础学习笔记(一)

    一.三元表达式 1.1 什么是三元表达式 由三元运算符组成的式子我们称为三元表达式 1.2 语法结构 条件表达式 ? 表达式1 : 表达式2 1.3 执行思路 如果表达式为结果真 则返回表达式1的值, ...

  8. Dive into TensorFlow系列(2)- 解析TF核心抽象op算子

    本文作者:李杰 TF计算图从逻辑层来讲,由op与tensor构成.op是项点代表计算单元,tensor是边代表op之间流动的数据内容,两者配合以数据流图的形式来表达计算图.那么op对应的物理层实现是什 ...

  9. i春秋Fuzzing

    先查看源码...没东西,抓包 发现也没什么,但是右边有个提示hint: ip,Large internal network(最大内网ip) 可能需要我们伪造代码进行访问,这还不简单,直接在reques ...

  10. Zookeeper的服务器的log4j升级为log4j2的升级方案(忽略配置化兼容问题)

    参考在线markdown编辑器: http://marxi.co/ Zookeeper的服务器的log4j升级为log4j2的升级方案(忽略配置化兼容问题) 目前希望可以升级将Zookeeper中lo ...