在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
通过使用 ASP.NET Core MVC 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码。 注意:Razor 页面的筛选方法。 内置筛选器处理一些任务,例如:
可以创建自定义筛选器,用于处理横切关注点。过滤器可以避免在action中编写一些重复性的代码。比如异常过滤器可以合并处理异常。 筛选器的工作原理筛选器管道在 MVC 选择了要执行的操作(controller中的action方法)之后运行。
筛选器类型每种筛选器类型都在筛选器管道中的不同阶段(上图中的mvc action invocation pipeline)执行。
//startup: public void ConfigureServices(IServiceCollection services) { services.AddMvc(action => { action.Filters.Add<AuthorizationFilter>(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } //authorizationfilter: public class AuthorizationFilter : IAsyncAuthorizationFilter { private readonly ILoggerFactory loggerFactory; public AuthorizationFilter(ILoggerFactory loggerFactory) { this.loggerFactory = loggerFactory; } public Task OnAuthorizationAsync(AuthorizationFilterContext context) { var logger = loggerFactory.CreateLogger<AuthorizationFilter>(); logger.LogWarning($"authorization filter is executing now ,target action is :{context.ActionDescriptor.DisplayName}"); return Task.CompletedTask; } }
//startup: public void ConfigureServices(IServiceCollection services) { services.AddMvc(action => { action.Filters.Add<AuthorizationFilter>(); action.Filters.Add<ResourceFilter>(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } //resourcefilter: public class ResourceFilter : IAsyncResourceFilter { private readonly ILoggerFactory loggerFactory; public ResourceFilter(ILoggerFactory loggerFactory) { this.loggerFactory = loggerFactory; } public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { var logger = loggerFactory.CreateLogger<ResourceFilter>(); logger.LogWarning($"resource filter is executing now,valueproviderfactories count:{context.ValueProviderFactories.Count}"); var executedContext = await next(); logger.LogWarning($"resource filter is executed now ,result's type is {executedContext.Result.GetType().Name}"); } }
//startup: public void ConfigureServices(IServiceCollection services) { services.AddMvc(action => { action.Filters.Add<ActionsFilter>(); action.Filters.Add<AuthorizationFilter>(); action.Filters.Add<ResourceFilter>(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } //actionsfilter public class ActionsFilter : IAsyncActionFilter { private readonly ILoggerFactory factory; public ActionsFilter(ILoggerFactory factory) { this.factory = factory; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var logger = factory.CreateLogger<ActionsFilter>(); logger.LogWarning($"action filter is executing new ,context.modelstate:{context.ModelState.IsValid}"); var executedContext = await next(); logger.LogWarning($"action filter is executed now,executedContext controller:{executedContext.Controller.ToString()}"); } }
//startup: public void ConfigureServices(IServiceCollection services) { services.AddMvc(action => { action.Filters.Add<ActionsFilter>(); action.Filters.Add<AuthorizationFilter>(); action.Filters.Add<ResourceFilter>(); action.Filters.Add<ExceptionsFilter>(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } //exceptionsfilter: public class ExceptionsFilter : IAsyncExceptionFilter { private readonly ILoggerFactory loggerFactory; public ExceptionsFilter(ILoggerFactory loggerFactory) { this.loggerFactory = loggerFactory; } public Task OnExceptionAsync(ExceptionContext context) { var logger = loggerFactory.CreateLogger<ExceptionsFilter>(); logger.LogWarning($"some exception's happened,exception's message:{context.Exception.Message}"); 上面的日志打印结果可以看出exception filter实在authorization filter和resource filter以及action filter之后执行的它能捕获的异常是在action执行过程中发生的异常。所以,如果在authorization filter或者resource filter中发生异常的话,它是没有办法捕获的,可以做一个测验:将authorization filter中抛出一个异常: 可以看到这个异常是被直接抛出来了,并没有被exception handler中进行处理。接着改在resource filter中抛出一个异常,看看: 同样,在resource filter中抛出的异常exception filter也是处理不了的。也就是说在筛选器管道中,处于exception筛选器执行之前而执行的代码抛出的异常,exception筛选器是处理不了的。要想捕获程序的全局异常,我觉得应该在中间件中定义对异常的捕获。这个结论还没有进行证实,有时间再讨论。
//startup: public void ConfigureServices(IServiceCollection services) { services.AddMvc(action => { action.Filters.Add<ActionsFilter>(); action.Filters.Add<AuthorizationFilter>(); action.Filters.Add<ResourceFilter>(); action.Filters.Add<ExceptionsFilter>(); action.Filters.Add<ResultFilter>(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } //resultfilter: public class ResultFilter : IAsyncResultFilter { private readonly ILoggerFactory loggerFactory; public ResultFilter(ILoggerFactory loggerFactory) { this.loggerFactory = loggerFactory; } public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { var logger = loggerFactory.CreateLogger<ResultFilter>(); logger.LogWarning($"result filter is executing, context.result is :{context.Result.GetType().Name}"); var executedContext = await next(); logger.LogWarning($"result filter is executed ,context.result is {executedContext.Result.GetType().Name}"); } } 上面的结果是action中没有抛出异常,正常执行的结果,如果在action中抛出异常: 上下对比一下会发现,result filter只会在action正常执行没有抛出异常之后才会执行。exception filter是会捕获action抛出的异常。 下图展示了这些筛选器类型在筛选器管道中的交互方式。 实现通过不同的接口定义,筛选器同时支持同步和异步实现。例如我上面举的例子全部都是用异步的方式实现的。 例如,在调用操作方法之前调用
using FiltersSample.Helper; using Microsoft.AspNetCore.Mvc.Filters; namespace FiltersSample.Filters { public class SampleActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // do something before the action executes } public void OnActionExecuted(ActionExecutedContext context) { // do something after the action executes } } } 例如, ActionFilterAttribute 类实现
注意:同步和异步的只需要实现一个就行,如果两个都实现了,会优先执行异步版本的。 篇幅太长,再来一片吧。 |
请发表评论