如何使用DispatchProxy拦截标记自定义特性的方法?
实现基于DispatchProxy的特性标记方法拦截
1. 完善InterceptorProxy的核心拦截逻辑
在你的InterceptorProxy的Invoke方法中增加特性判断,仅对标记了DispachedAttribute的方法执行拦截逻辑,未标记的直接调用原方法:
public class InterceptorProxy<T> : DispatchProxy { private T _target; // 可自定义拦截处理逻辑的委托 private Action<MethodInfo, object[], object> _interceptHandler; public static T Create(T target, Action<MethodInfo, object[], object> interceptHandler) { var proxy = Create<T, InterceptorProxy<T>>() as InterceptorProxy<T>; proxy._target = target; proxy._interceptHandler = interceptHandler; return proxy as T; } protected override object Invoke(MethodInfo targetMethod, object[] args) { // 检查当前方法是否标记了目标特性 var isDispached = targetMethod.GetCustomAttributes(typeof(DispachedAttribute), inherit: true).Any(); object result; if (isDispached) { // 拦截前置操作,比如日志、参数校验 Console.WriteLine($"[拦截前置] 方法{targetMethod.Name}开始执行"); // 调用原始方法 result = targetMethod.Invoke(_target, args); // 拦截后置操作,比如结果处理、性能统计 _interceptHandler?.Invoke(targetMethod, args, result); Console.WriteLine($"[拦截后置] 方法{targetMethod.Name}执行完成"); } else { // 未标记特性,直接执行原方法 result = targetMethod.Invoke(_target, args); } return result; } }
2. 封装代理工厂实现一键创建代理
写一个静态工厂类,避免重复编写代理创建代码,让业务代码可以快速拿到带拦截逻辑的实例:
public static class ProxyFactory { public static T CreateProxy<T>(T target) where T : class { return InterceptorProxy<T>.Create(target, (method, args, result) => { // 这里可以自定义具体的拦截逻辑,比如记录方法执行日志 Console.WriteLine($"[拦截记录] 方法{method.Name},参数:{string.Join(", ", args)},返回值:{result}"); }); } }
3. 普通类的拦截自动生效
业务代码中直接通过工厂创建实例,拿到的就是已开启拦截的代理对象:
public class TaskService { [Dispached] public void Run() { Console.WriteLine("执行Run业务逻辑"); } public void NormalMethod() { Console.WriteLine("这个方法不会被拦截"); } } // 使用示例 var service = ProxyFactory.CreateProxy(new TaskService()); service.Run(); // 触发拦截 service.NormalMethod(); // 无拦截
4. MVC控制器的拦截自动生效
如果是ASP.NET MVC控制器,结合依赖注入实现自动注入代理对象:
4.1 在DI容器中注册代理逻辑
在Program.cs中替换原始服务的注册逻辑,让容器返回代理对象:
builder.Services.AddScoped<TaskService>(); // 注册代理版本的服务 builder.Services.AddScoped<ITaskService>(sp => { var originalService = sp.GetRequiredService<TaskService>(); return ProxyFactory.CreateProxy(originalService); });
4.2 控制器构造注入
控制器中直接注入接口,拿到的就是带拦截逻辑的代理实例,标记了特性的方法自动触发拦截:
public class HomeController : Controller { private readonly ITaskService _taskService; public HomeController(ITaskService taskService) { _taskService = taskService; } public IActionResult Index() { _taskService.Run(); // 自动执行拦截逻辑 return View(); } }
关键注意事项
- 被代理的类不能是
sealed(密封类),DispatchProxy需要生成继承自目标类的代理子类。 - 如果要拦截控制器自身的方法(而非依赖服务),可以自定义控制器激活器,在创建控制器实例时通过
ProxyFactory生成代理对象。
内容的提问来源于stack exchange,提问作者barteloma
相关产品推荐
相关产品推荐

