过滤器及拦截器
ActionFilterAttribute
是ASP.NET MVC 框架引入的特性,随着ASP.NET MVC 的发展不断完善。ASP.NET MVC 框架于 2009 年发布,为开发者提供了基于 MVC 模式构建 Web 应用程序的方式,ActionFilterAttribute
作为其中重要的一部分,用于在控制器动作执行前后插入自定义逻辑。之后,随着ASP.NET Core 的推出,ActionFilterAttribute
也得到了延续和改进,更好地适应了现代 Web 开发的需求。
原理
ActionFilterAttribute
是一种过滤器,它基于 AOP(面向切面编程)的思想。在ASP.NET MVC 和ASP.NET Core 中,过滤器是一种特殊的类,用于在请求处理管道的特定阶段执行代码。ActionFilterAttribute
主要有两个关键的方法:
OnActionExecuting
:在控制器动作执行之前调用。可以在此方法中对请求进行预处理,例如验证请求参数、记录日志等。如果在这个方法中设置了filterContext.Result
属性,那么动作方法将不会被执行,直接返回该结果。OnActionExecuted
:在控制器动作执行之后调用。可以在此方法中对响应进行后处理,例如修改响应内容、记录响应时间等。
作用
- 验证和授权:可以在动作执行前验证请求参数或用户权限,确保只有符合条件的请求才能执行动作。
- 日志记录:在动作执行前后记录日志,方便调试和监控。
- 缓存:在动作执行前检查缓存,如果缓存存在则直接返回缓存结果,避免重复执行动作。
- 异常处理:在动作执行过程中捕获异常,并进行统一处理。
使用案例
以下是一个使用 ActionFilterAttribute
对接口入参进行优先判断的示例。假设我们有一个简单的 Web API,要求传入的参数 id
必须大于 0。
using System;
using System.Web.Http.Filters;
using System.Net;
using System.Net.Http;// 自定义ActionFilterAttribute
public class ParameterValidationFilterAttribute : ActionFilterAttribute
{public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext){// 获取请求参数var id = actionContext.ActionArguments.ContainsKey("id") ? (int?)actionContext.ActionArguments["id"] : null;// 验证参数if (id == null || id <= 0){// 参数验证失败,返回错误信息actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,"参数 id 必须大于 0。");}}
}// 控制器
public class MyController : System.Web.Http.ApiController
{[ParameterValidationFilter]public IHttpActionResult Get(int id){// 只有参数验证通过才会执行到这里return Ok($"你传入的 id 是: {id}");}
}
代码解释
- 自定义过滤器
ParameterValidationFilterAttribute
:继承自ActionFilterAttribute
,重写OnActionExecuting
方法。在该方法中,获取请求参数id
,并验证其是否大于 0。如果验证失败,设置actionContext.Response
属性,返回一个包含错误信息的 HTTP 响应。 - 控制器
MyController
:在Get
方法上应用[ParameterValidationFilter]
特性,这样在执行Get
方法之前,会先执行ParameterValidationFilterAttribute
的OnActionExecuting
方法进行参数验证。只有参数验证通过,才会继续执行Get
方法的内容。
这个示例展示了如何使用 ActionFilterAttribute
对接口的入参进行优先判断,确保只有符合条件的请求才能执行接口内的内容。
其他
在 .NET 里,除了 ActionFilterAttribute
所在的过滤器体系,有一些具备相似功能或者可用于实现相似逻辑的库与机制,下面为你详细介绍:
1. 授权过滤器(Authorization Filters)
- 相关 DLL:
Microsoft.AspNetCore.Authorization
(ASP.NET Core);System.Web.Mvc
(ASP.NET MVC)。 - 原理:在动作方法执行之前,它的作用是验证用户是否具备访问该资源的权限。它是基于角色、策略或者自定义授权规则来判定的。
- 作用:对用户访问资源进行管控,避免未授权的用户访问特定的接口或者页面。
- 示例代码:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;[Authorize(Roles = "Admin")]
public class AdminController : Controller
{public IActionResult Index(){return View();}
}
在这个示例中,AuthorizeAttribute
充当授权过滤器,它保证只有具备 “Admin” 角色的用户才能访问 AdminController
的 Index
方法。
2. 异常过滤器(Exception Filters)
- 相关 DLL:
Microsoft.AspNetCore.Mvc.Core
(ASP.NET Core);System.Web.Mvc
(ASP.NET MVC)。 - 原理:在动作方法执行期间一旦发生异常,异常过滤器就会捕获该异常,并且能够对异常进行统一处理。
- 作用:实现全局异常处理,增强应用程序的健壮性与用户体验。
- 示例代码:
csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{public override void OnException(ExceptionContext context){// 记录日志Console.WriteLine($"An exception occurred: {context.Exception.Message}");// 返回统一的错误响应context.Result = new ObjectResult("An error occurred. Please try again later."){StatusCode = 500};}
}[CustomExceptionFilter]
public class MyController : Controller
{public IActionResult Index(){throw new Exception("Something went wrong!");}
}
在这个例子中,CustomExceptionFilterAttribute
是自定义的异常过滤器,它会捕获 Index
方法抛出的异常,记录日志并返回统一的错误响应。
3. 结果过滤器(Result Filters)
- 相关 DLL:
Microsoft.AspNetCore.Mvc.Core
(ASP.NET Core);System.Web.Mvc
(ASP.NET MVC)。 - 原理:在动作方法执行之后、结果返回之前被调用,可用于对动作结果进行修改或者后处理。
- 作用:对响应结果进行统一处理,例如添加响应头、压缩响应内容等。
- 示例代码:
csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;public class CustomResultFilterAttribute : ResultFilterAttribute
{public override void OnResultExecuting(ResultExecutingContext context){// 在结果执行前添加响应头context.HttpContext.Response.Headers.Add("X-Custom-Header", "Custom Value");base.OnResultExecuting(context);}
}[CustomResultFilter]
public class MyController : Controller
{public IActionResult Index(){return Ok("Hello, World!");}
}
在这个示例中,CustomResultFilterAttribute
是自定义的结果过滤器,它会在 Index
方法返回结果之前添加一个自定义的响应头。
4. 管道过滤器(Pipeline Filters)
- 相关 DLL:
Microsoft.AspNetCore.Mvc.Core
(ASP.NET Core)。 - 原理:它是 ASP.NET Core 里的一种新过滤器类型,能够在请求处理管道的多个阶段进行拦截和处理。
- 作用:实现更灵活、更细粒度的请求处理逻辑。
- 示例代码:
using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;public class CustomPipelineFilter : IAsyncResourceFilter
{public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next){// 在资源执行前处理// ...var resultContext = await next();// 在资源执行后处理// ...}
}
在这个例子中,CustomPipelineFilter
实现了 IAsyncResourceFilter
接口,可在资源执行前后进行处理。
Castle.Core.dll
Castle.Core.dll
算是具备与 ActionFilterAttribute
类似功能的库,下面从几个方面为你分析:
功能概述
Castle.Core.dll
是 Castle 项目中的核心库,该项目提供了一系列的工具和框架,其中的动态代理(Dynamic Proxy)组件和 ActionFilterAttribute
一样,都能实现面向切面编程(AOP)的功能。而 ActionFilterAttribute
是 ASP.NET 中用于在控制器动作执行前后插入自定义逻辑的特性,也是 AOP 思想的一种体现。
实现原理对比
ActionFilterAttribute
:在 ASP.NET 框架里,它是基于过滤器管道来工作的。当请求进入 MVC 或 Web API 应用时,框架会按特定顺序执行不同类型的过滤器,ActionFilterAttribute
可在动作方法执行前后执行代码。Castle.Core
的动态代理:借助运行时生成代理类,将横切关注点(如日志记录、事务管理等)织入到目标对象的方法调用中。它在不修改目标对象代码的情况下,为其添加额外功能。
作用对比
ActionFilterAttribute
:主要用于 ASP.NET 应用中控制器动作的预处理和后处理,像参数验证、日志记录、性能监控等,一般在 Web 开发场景下使用。Castle.Core
:可用于各类 .NET 应用程序,不仅能在 Web 应用中使用,还能在桌面应用、服务应用等场景使用。它能实现日志记录、事务管理、缓存、安全检查等横切关注点,具有更广泛的适用性。
使用案例
下面是使用 Castle.Core
实现简单 AOP 功能的示例:
using Castle.DynamicProxy;
using System;// 定义一个拦截器类
public class LoggingInterceptor : IInterceptor
{public void Intercept(IInvocation invocation){Console.WriteLine($"Before method {invocation.Method.Name}");invocation.Proceed();Console.WriteLine($"After method {invocation.Method.Name}");}
}// 定义一个接口
public interface IService
{void DoSomething();
}// 实现接口
public class MyService : IService
{public void DoSomething(){Console.WriteLine("Doing something...");}
}class Program
{static void Main(){// 创建代理生成器var proxyGenerator = new ProxyGenerator();// 创建拦截器实例var interceptor = new LoggingInterceptor();// 创建目标对象var service = new MyService();// 生成代理对象var proxy = proxyGenerator.CreateInterfaceProxyWithTarget<IService>(service, interceptor);// 调用代理对象的方法proxy.DoSomething();}
}
代码解释
LoggingInterceptor
类实现了IInterceptor
接口,在Intercept
方法中定义了在目标方法执行前后要执行的逻辑。MyService
类实现了IService
接口,代表目标对象。- 在
Main
方法中,使用ProxyGenerator
生成代理对象,并将拦截器和目标对象关联起来。调用代理对象的方法时,拦截器的逻辑就会被执行。
从上述分析可以看出,Castle.Core.dll
能实现和 ActionFilterAttribute
类似的 AOP 功能,不过它的应用场景更为广泛。
1. Autofac.Extras.DynamicProxy
- 概述:Autofac 是一个流行的依赖注入容器,而
Autofac.Extras.DynamicProxy
是它的一个扩展,结合了 Autofac 的依赖注入能力与 Castle DynamicProxy 的 AOP 功能。它允许你在应用程序中使用 AOP 模式,将横切关注点(如日志记录、事务管理等)应用到服务的方法调用上。 - 原理:借助 Autofac 的容器来管理对象的生命周期,同时利用 Castle DynamicProxy 在运行时生成代理类,把拦截器逻辑织入到目标对象的方法调用中。
- 使用案例
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using System;// 定义拦截器
public class LoggingInterceptor : IInterceptor
{public void Intercept(IInvocation invocation){Console.WriteLine($"Before method: {invocation.Method.Name}");invocation.Proceed();Console.WriteLine($"After method: {invocation.Method.Name}");}
}// 定义服务接口
public interface IMyService
{void DoWork();
}// 实现服务
public class MyService : IMyService
{public void DoWork(){Console.WriteLine("Doing work...");}
}class Program
{static void Main(){var builder = new ContainerBuilder();// 注册拦截器builder.RegisterType<LoggingInterceptor>();// 注册服务并应用拦截器builder.RegisterType<MyService>().As<IMyService>().EnableInterfaceInterceptors().InterceptedBy(typeof(LoggingInterceptor));var container = builder.Build();var service = container.Resolve<IMyService>();service.DoWork();}
}
2. PostSharp
- 概述:PostSharp 是一个强大的 AOP 框架,它通过编译时织入的方式将横切关注点集成到代码中。与运行时生成代理不同,PostSharp 在编译时修改 IL 代码,把额外的逻辑插入到目标方法中。
- 原理:在代码编译期间,PostSharp 分析代码中的特性(Attributes),并根据这些特性对 IL 代码进行修改,从而实现 AOP 功能。
- 使用案例
using PostSharp.Aspects;
using System;// 定义切面
[Serializable]
public class LoggingAspect : OnMethodBoundaryAspect
{public override void OnEntry(MethodExecutionArgs args){Console.WriteLine($"Before method: {args.Method.Name}");}public override void OnExit(MethodExecutionArgs args){Console.WriteLine($"After method: {args.Method.Name}");}
}// 应用切面
[LoggingAspect]
public class MyClass
{public void MyMethod(){Console.WriteLine("Method is executing...");}
}class Program
{static void Main(){var obj = new MyClass();obj.MyMethod();}
}
3.NLog.Extensions.MicrosoftLogging
- 概述:NLog 是一个用于 .NET 平台的日志记录库,
NLog.Extensions.MicrosoftLogging
是它与 Microsoft 日志框架集成的扩展。虽然它主要用于日志记录,但可以通过配置和自定义实现类似ActionFilterAttribute
的功能,例如在方法执行前后记录日志。 - 原理:借助 Microsoft 的日志抽象层,将日志记录逻辑集成到应用程序中。可以在不同的代码位置插入日志记录语句,实现对方法执行过程的监控。
- 使用案例
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using System;public class MyService
{private readonly ILogger<MyService> _logger;public MyService(ILogger<MyService> logger){_logger = logger;}public void DoSomething(){_logger.LogInformation("Before doing something");Console.WriteLine("Doing something...");_logger.LogInformation("After doing something");}
}class Program
{static void Main(){var serviceCollection = new ServiceCollection();serviceCollection.AddLogging(loggingBuilder =>{loggingBuilder.ClearProviders();loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);loggingBuilder.AddNLog();});serviceCollection.AddTransient<MyService>();var serviceProvider = serviceCollection.BuildServiceProvider();var myService = serviceProvider.GetRequiredService<MyService>();myService.DoSomething();}
}
这些库或机制都以不同的方式实现了面向切面编程的思想,能够在方法执行前后插入自定义逻辑,与 ActionFilterAttribute
的功能有相似之处。