news 2026/2/2 1:58:41

C#进阶疗法 -- 过滤器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#进阶疗法 -- 过滤器

ASP.NET Core 代码过滤器入门指南:实现统一处理

什么是代码过滤器?

代码过滤器是 ASP.NET Core 中的一种组件,允许我们在请求处理管道的不同阶段执行自定义逻辑。它们提供了一种声明式的方式来处理横切关注点(cross-cutting concerns),如异常处理、日志记录、授权验证等。

为什么需要代码过滤器?

在传统的 MVC 应用程序中,如果我们需要为多个控制器或操作方法添加相同的逻辑(比如异常处理),通常需要在每个控制器或方法中重复编写这些代码,这会导致代码冗余和维护困难。使用代码过滤器,我们可以将这些通用逻辑集中到一个地方,然后应用到多个控制器或操作方法上,从而减少代码冗余,提高代码的可维护性。

ASP.NET Core 中的过滤器类型

ASP.NET Core 提供了多种类型的过滤器,每种类型在请求处理管道的不同阶段执行:

  1. 授权过滤器(Authorization Filters):在管道的最早阶段执行,用于验证用户是否有权限访问资源。
  2. 资源过滤器(Resource Filters):在授权过滤器之后执行,在模型绑定之前和结果执行之后执行。
  3. 操作过滤器(Action Filters):在操作方法执行前后执行,用于处理操作方法相关的逻辑。
  4. 异常过滤器(Exception Filters):在发生未处理异常时执行,用于捕获和处理异常。
  5. 结果过滤器(Result Filters):在操作方法执行完成后,在结果执行前后执行,用于处理结果相关的逻辑。

如何实现和使用代码过滤器?

在 ASP.NET Core 中,我们可以通过实现相应的接口来创建自定义过滤器,然后通过依赖注入或特性的方式将其应用到控制器或操作方法上。下面我们将通过具体的示例来演示如何实现和使用代码过滤器。

步骤 1:创建过滤器类

1.1 创建异常过滤器

首先,我们创建一个异常过滤器,用于捕获和处理异常:

usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.AspNetCore.Mvc.Filters;namespaceFrameLearning.BasicComponents{/// <summary>/// 错误过滤器/// </summary>publicclassGlobalExceptionFilter:IExceptionFilter{/// <summary>/// 提供关于Web应用程序运行环境/// </summary>privatereadonlyIWebHostEnvironment_environment;/// <summary>/// 日志组件/// </summary>privatereadonlyILogger<GlobalExceptionFilter>_logger;publicGlobalExceptionFilter(ILogger<GlobalExceptionFilter>logger,IWebHostEnvironmentenvironment){_logger=logger;_environment=environment;}publicvoidOnException(ExceptionContextcontext){Exceptionex=context.Exception;stringerrMsg="过滤器捕获错误:"+ex.Message;ApiResponse<object>apiResponse=newApiResponse<object>();if(context.Exception.GetType()==typeof(BusinessException)){varerror=(BusinessException)context.Exception;apiResponse.Code=500;apiResponse.Success=false;apiResponse.Message=error.AdditionalInformation+","+ex.Message;apiResponse.Data=null;_logger.LogInformation(errMsg);}elseif(context.Exception.GetType()==typeof(Exception)){apiResponse.Code=500;apiResponse.Success=false;apiResponse.Message=ex.Message;apiResponse.Data=null;_logger.LogInformation(errMsg);}else{apiResponse.Code=500;apiResponse.Success=false;apiResponse.Message=ex.Message;apiResponse.Data=null;_logger.LogInformation(errMsg);}// 设置响应内容context.Result=newObjectResult(apiResponse){StatusCode=apiResponse.Code};// 标记异常已处理context.ExceptionHandled=true;}}}

在这个示例中,我们创建了一个GlobalExceptionFilter类,它实现了IExceptionFilter接口的OnException方法。在OnException方法中,我们首先获取异常对象,然后根据异常类型创建不同的响应对象,最后设置响应内容并标记异常已处理。

1.2 创建结果过滤器

接下来,我们创建一个结果过滤器,用于包装响应结果:

usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.AspNetCore.Mvc.Filters;namespaceFrameLearning.BasicComponents{publicclassResponseFilter:IAsyncResultFilter{publicasyncTaskOnResultExecutionAsync(ResultExecutingContextcontext,ResultExecutionDelegatenext){if(context.ResultisObjectResultobjectResult){if(objectResult.StatusCode==200||objectResult.StatusCode==null){context.Result=newObjectResult(newApiResponse<object>{Code=200,Success=true,Message="过滤器-操作成功",Data=objectResult.Value}){StatusCode=200};awaitnext();}elseif(objectResult.StatusCode==401){context.Result=newObjectResult(newApiResponse<object>{Code=401,Success=false,Message="没有授权,无法直接请求该接口,请登录后访问!",Data=objectResult.Value}){StatusCode=401};awaitnext();}}// 继续执行管道awaitnext();}}}

在这个示例中,我们创建了一个ResponseFilter类,它实现了IAsyncResultFilter接口的OnResultExecutionAsync方法。在OnResultExecutionAsync方法中,我们首先检查响应结果是否为ObjectResult,然后根据状态码创建不同的响应对象,最后继续执行管道。

1.3 创建操作过滤器

最后,我们创建一个操作过滤器,用于在方法执行前后执行一些逻辑:

usingMicrosoft.AspNetCore.Mvc.Filters;namespaceFrameLearning.BasicComponents{/// <summary>/// 通用过滤器/// </summary>publicclassGlobalActionFilter:IActionFilter{/// <summary>/// 请求返回时执行/// </summary>/// <param name="context"></param>publicvoidOnActionExecuted(ActionExecutedContextcontext){Console.WriteLine("方法完成之后进入");}/// <summary>/// 请求进入时执行/// </summary>/// <param name="context"></param>publicvoidOnActionExecuting(ActionExecutingContextcontext){Console.WriteLine("方法完成之前进入");}}}

在这个示例中,我们创建了一个GlobalActionFilter类,它实现了IActionFilter接口的OnActionExecutingOnActionExecuted方法。在OnActionExecuting方法中,我们在方法执行前打印一条日志;在OnActionExecuted方法中,我们在方法执行后打印一条日志。

步骤 2:创建响应模型类

为了统一响应格式,我们需要创建一个响应模型类:

namespaceFrameLearning.BasicComponents{publicclassApiResponse<T>{publicintCode{get;set;}publicboolSuccess{get;set;}=true;publicTData{get;set;}publicstringMessage{get;set;}}}

在这个示例中,我们创建了一个ApiResponse<T>类,它包含CodeSuccessDataMessage四个属性,用于表示响应的状态码、是否成功、数据和消息。

步骤 3:创建业务异常类

为了处理业务异常,我们需要创建一个业务异常类:

namespaceFrameLearning.BasicComponents{publicclassBusinessException:Exception{publicstringAdditionalInformation{get;set;}publicBusinessException(stringadditionalInformation,stringmessage,ExceptioninnerException):base(message,innerException){AdditionalInformation=additionalInformation;}publicBusinessException(stringmessage,ExceptioninnerException):base(message,innerException){}publicBusinessException(stringmessage):base(message){}}}

在这个示例中,我们创建了一个BusinessException类,它继承自Exception类,添加了一个AdditionalInformation属性,用于存储额外的错误信息。

步骤 4:注册过滤器

Program.cs文件中,我们需要注册过滤器:

// Add services to the container.builder.Services.AddScoped<GlobalExceptionFilter>();builder.Services.AddScoped<ResponseFilter>();builder.Services.AddScoped<GlobalActionFilter>();// Add controllers with filtersbuilder.Services.AddControllers(p=>{p.Filters.AddService<GlobalExceptionFilter>();// 异常处理过滤器p.Filters.AddService<ResponseFilter>();// 统一响应过滤器p.Filters.AddService<GlobalActionFilter>();// 通用动作过滤器});

在这个示例中,我们首先注册了三个过滤器服务,然后在添加控制器时将这些过滤器添加到控制器的过滤器集合中。

步骤 5:使用过滤器

现在,我们可以在控制器中使用过滤器了。由于我们已经将过滤器注册为全局过滤器,所以它们会自动应用到所有控制器和操作方法上。

5.1 抛出异常

在控制器中,我们可以抛出异常,异常过滤器会自动捕获和处理这些异常:

[HttpGet]publicIActionResultGet(){try{thrownewException("");varforecasts=Enumerable.Range(1,5).Select(index=>newWeatherForecast{Date=DateOnly.FromDateTime(DateTime.Now.AddDays(index)),TemperatureC=Random.Shared.Next(-20,55),Summary=Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();returnOk(forecasts);}catch(Exceptionex){thrownewBusinessException("业务错误",ex.Message,ex);}}

在这个示例中,我们在Get方法中抛出了一个异常,然后在catch块中抛出了一个BusinessException异常,异常过滤器会自动捕获和处理这个异常。

5.2 返回结果

在控制器中,我们可以返回结果,结果过滤器会自动包装这些结果:

[HttpPost]publicIActionResultPost(TestBotestBo){try{returnOk(testBo);}catch(Exceptionex){thrownewBusinessException("",ex.Message,ex);}}

在这个示例中,我们在Post方法中返回了一个Ok结果,结果过滤器会自动包装这个结果。

ASP.NET Core 中的过滤器作用域

ASP.NET Core 中的过滤器可以应用在不同的作用域上:

  1. 全局作用域:应用到所有控制器和操作方法上,通过在Program.cs文件中注册。
  2. 控制器作用域:应用到特定控制器的所有操作方法上,通过在控制器类上添加特性。
  3. 操作方法作用域:应用到特定的操作方法上,通过在操作方法上添加特性。

示例:控制器作用域过滤器

[ServiceFilter(typeof(LogFilter))]publicclassHomeController:ControllerBase{// 操作方法}

示例:操作方法作用域过滤器

publicclassHomeController:ControllerBase{[ServiceFilter(typeof(LogFilter))]publicIActionResultIndex(){// 方法体}}

过滤器的执行顺序

ASP.NET Core 中的过滤器按照以下顺序执行:

  1. 授权过滤器:在管道的最早阶段执行。
  2. 资源过滤器:在授权过滤器之后执行。
  3. 操作过滤器:在资源过滤器之后执行。
  4. 异常过滤器:在发生异常时执行。
  5. 结果过滤器:在操作方法执行完成后执行。

过滤器的应用场景

过滤器在很多场景下都非常有用,下面列举几个常见的应用场景:

1. 异常处理

使用异常过滤器,我们可以统一处理所有控制器和操作方法中的异常,从而减少代码冗余,提高代码的可维护性。

2. 响应包装

使用结果过滤器,我们可以统一包装所有控制器和操作方法的响应结果,从而确保响应格式的一致性。

3. 日志记录

使用操作过滤器,我们可以在方法执行前后记录日志,从而了解方法的执行情况。

4. 性能监控

使用资源过滤器,我们可以监控方法的执行时间,从而了解哪些方法执行较慢,需要优化:

publicclassPerformanceFilter:IResourceFilter{privatereadonlyILogger<PerformanceFilter>_logger;privateStopwatch_stopwatch;publicPerformanceFilter(ILogger<PerformanceFilter>logger){_logger=logger;}publicvoidOnResourceExecuting(ResourceExecutingContextcontext){_stopwatch=Stopwatch.StartNew();}publicvoidOnResourceExecuted(ResourceExecutedContextcontext){_stopwatch.Stop();_logger.LogInformation($"方法{context.ActionDescriptor.DisplayName}执行时间:{_stopwatch.ElapsedMilliseconds}ms");}}

5. 授权验证

使用授权过滤器,我们可以验证用户是否有权限访问资源:

publicclassCustomAuthorizeFilter:IAuthorizationFilter{publicvoidOnAuthorization(AuthorizationFilterContextcontext){varuser=context.HttpContext.User;if(!user.Identity.IsAuthenticated){context.Result=newUnauthorizedResult();return;}// 验证用户是否有权限访问资源// ...}}

总结

代码过滤器是 ASP.NET Core 中的一种强大组件,允许我们在请求处理管道的不同阶段执行自定义逻辑。使用代码过滤器,我们可以将通用逻辑集中到一个地方,然后应用到多个控制器或操作方法上,从而减少代码冗余,提高代码的可维护性。

ASP.NET Core 提供了多种类型的过滤器,每种类型在请求处理管道的不同阶段执行。我们可以通过实现相应的接口来创建自定义过滤器,然后通过依赖注入或特性的方式将其应用到控制器或操作方法上。

在实际应用中,我们可以根据具体的需求,创建不同类型的过滤器,比如异常处理过滤器、响应包装过滤器、日志记录过滤器、性能监控过滤器、授权验证过滤器等,从而实现各种横切关注点的分离。

希望本文对你理解和使用 ASP.NET Core 代码过滤器有所帮助!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/1 6:05:41

c#进阶疗法 -jwt+授权

ASP.NET Core JWT 认证与授权实战指南 什么是 JWT&#xff1f; JWT&#xff08;JSON Web Token&#xff09;是一种基于 JSON 的开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在各方之间安全地传输信息。JWT 可以被验证和信任&#xff0c;因为它是数字签名的。 JWT…

作者头像 李华
网站建设 2026/1/31 11:49:20

如何在30分钟内完成Spring Boot 3与MyBatis-Plus的无缝对接?真相在这里

第一章&#xff1a;Spring Boot 3与MyBatis-Plus整合概述在现代Java后端开发中&#xff0c;Spring Boot 3以其自动配置、起步依赖和响应式编程支持等特性&#xff0c;成为构建微服务架构的首选框架。与此同时&#xff0c;MyBatis-Plus作为MyBatis的增强工具&#xff0c;在简化C…

作者头像 李华
网站建设 2026/2/1 5:46:43

6.4 守门员机制:使用 Kyverno 实施 K8s 准入控制与安全策略

6.4 守门员机制:使用 Kyverno 实施 K8s 准入控制与安全策略 1. 引言:把“应当如此”写成策略 准入控制是最后一道关口。把“安全与规范”从检查清单,变为可执行的策略。Kyverno 使用原生 YAML 模式,无需学习 Rego 即可编写策略,适合大规模推广。 2. Kyverno 策略类型 Va…

作者头像 李华
网站建设 2026/1/31 17:37:38

前端开发者如何在WordPress中实现Excel公式动态绑定?

要求&#xff1a;开源&#xff0c;免费&#xff0c;技术支持 博客&#xff1a;WordPress 开发语言&#xff1a;PHP 数据库&#xff1a;MySQL 功能&#xff1a;导入Word,导入Excel,导入PPT(PowerPoint),导入PDF,复制粘贴word,导入微信公众号内容,web截屏 平台&#xff1a;Window…

作者头像 李华
网站建设 2026/2/1 23:25:20

国产化替代中WordPress如何兼容信创环境公式编辑?

要求&#xff1a;开源&#xff0c;免费&#xff0c;技术支持 博客&#xff1a;WordPress 开发语言&#xff1a;PHP 数据库&#xff1a;MySQL 功能&#xff1a;导入Word,导入Excel,导入PPT(PowerPoint),导入PDF,复制粘贴word,导入微信公众号内容,web截屏 平台&#xff1a;Window…

作者头像 李华
网站建设 2026/1/30 13:42:41

有没有开源的大文件上传组件推荐?

今天早上又有网友加我微信&#xff0c;实际上我的微信号之前就已经在网上公开了&#xff0c;但是很多网友还是说找不到&#xff0c;这个就真没办法了。 昨天晚上又有一个网友给我发私信问了这个问题&#xff0c;他也是刚接触这一块&#xff0c;对这块的技术不是很了解&#xff…

作者头像 李华