news 2026/4/15 21:08:16

C#进阶疗法 -- 拦截器

作者头像

张小明

前端开发工程师

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

代码拦截器入门指南:使用 Castle.DynamicProxy 实现方法拦截

什么是代码拦截器?

代码拦截器是一种设计模式,允许我们在不修改原有代码的情况下,在方法执行前后插入自定义逻辑。这种技术在很多场景下非常有用,属于aop编程的范畴,比如:

  • 日志记录
  • 性能监控
  • 事务管理
  • 权限验证
  • 异常处理

为什么需要代码拦截器?

在传统的代码编写中,如果我们需要为多个方法添加相同的逻辑(比如日志记录),通常需要在每个方法中重复编写这些代码,这会导致代码冗余和维护困难。使用代码拦截器,我们可以将这些通用逻辑集中到一个地方,然后应用到多个方法上,从而减少代码冗余,提高代码的可维护性。

如何使用 Castle.DynamicProxy 实现代码拦截器?

Castle.DynamicProxy 是一个强大的库,允许我们在运行时创建代理对象,从而实现方法拦截。下面我们将通过一个具体的示例来演示如何使用 Castle.DynamicProxy 实现代码拦截器。

步骤 1:安装 Castle.DynamicProxy 包

首先,我们需要在项目中安装 Castle.DynamicProxy 包。可以通过 NuGet 包管理器或者命令行来安装:

dotnet add package Castle.Core

步骤 2:创建拦截器类

接下来,我们需要创建一个拦截器类,实现IInterceptor接口:

usingCastle.DynamicProxy;namespaceFrameLearning.BasicComponents{/// <summary>/// 拦截器/// </summary>publicclassLogInterceptor:IInterceptor{publicvoidIntercept(IInvocationinvocation){Console.WriteLine($"开始调用:{invocation.Method.Name}");// 执行原方法invocation.Proceed();Console.WriteLine($"结束调用:{invocation.Method.Name},返回值:{invocation.ReturnValue}");}}}

在这个示例中,我们创建了一个LogInterceptor类,它实现了IInterceptor接口的Intercept方法。在Intercept方法中,我们首先打印出方法名,表示方法开始调用,然后调用invocation.Proceed()执行原方法,最后打印出方法名和返回值,表示方法结束调用。

步骤 3:注册拦截器和目标服务

在 Program.cs 文件中,我们需要注册拦截器和目标服务:

// 注册 Castle.DynamicProxy.ProxyGenerator 服务builder.Services.AddSingleton<Castle.DynamicProxy.ProxyGenerator,Castle.DynamicProxy.ProxyGenerator>();// 注册拦截器builder.Services.AddScoped<LogInterceptor>();// 注册目标服务(使用代理)builder.Services.AddScoped<IUserServer>(provider=>{// 从 DI 容器获取代理生成器varproxyGenerator=provider.GetRequiredService<ProxyGenerator>();// 从 DI 容器获取拦截器varinterceptor=provider.GetRequiredService<LogInterceptor>();// 创建目标服务实例vartarget=newUserServer();// 生成代理对象并返回returnproxyGenerator.CreateInterfaceProxyWithTarget<IUserServer>(target,interceptor);});

在这个示例中,我们首先注册了Castle.DynamicProxy.ProxyGenerator服务,然后注册了LogInterceptor拦截器,最后注册了IUserServer服务,但是我们返回的不是UserServer的直接实例,而是通过proxyGenerator.CreateInterfaceProxyWithTarget方法创建的代理对象,这个代理对象会应用我们的LogInterceptor拦截器。

步骤 4:创建目标服务接口和实现

我们需要创建目标服务接口和实现,以便拦截器可以拦截其方法调用:

// IUserServer.csnamespaceFrameLearning.Servers{publicinterfaceIUserServer{publicList<string>GetRoles();}}// UserServer.csnamespaceFrameLearning.Servers{publicclassUserServer:IUserServer{publicList<string>GetRoles(){List<string>roles=newList<string>();roles.Add("Admin");returnroles;}}}

在这个示例中,我们创建了一个IUserServer接口,它有一个GetRoles方法,然后创建了一个UserServer类,实现了这个接口。

步骤 5:使用拦截器

现在,我们可以在控制器中使用IUserServer服务,拦截器会自动拦截其方法调用:

[HttpPost("login")][AllowAnonymous]publicIActionResultLogin([FromBody]UserCredentialscredentials){varroles=_userServer.GetRoles();// 生成tokenvartoken=_jwtService.GenerateToken(credentials.Username,roles);returnOk(newUserResponse{Username=credentials.Username,Token=token,Roles=roles});}

在这个示例中,当我们调用_userServer.GetRoles()方法时,LogInterceptor会自动拦截这个调用,在方法执行前后打印日志。

代码拦截器的应用场景

代码拦截器在很多场景下都非常有用,下面列举几个常见的应用场景:

1. 日志记录

如我们在示例中所示,我们可以使用拦截器在方法执行前后记录日志,这样可以方便我们了解方法的执行情况,而不需要在每个方法中手动添加日志代码。

2. 性能监控

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

publicclassPerformanceInterceptor:IInterceptor{privatereadonlyILogger<PerformanceInterceptor>_logger;publicPerformanceInterceptor(ILogger<PerformanceInterceptor>logger){_logger=logger;}publicvoidIntercept(IInvocationinvocation){varstopwatch=Stopwatch.StartNew();try{invocation.Proceed();}finally{stopwatch.Stop();_logger.LogInformation($"方法{invocation.Method.Name}执行时间:{stopwatch.ElapsedMilliseconds}ms");}}}

3. 事务管理

我们可以使用拦截器来管理事务,确保方法执行过程中的所有操作都在一个事务中:

publicclassTransactionInterceptor:IInterceptor{privatereadonlyIDbContext_dbContext;publicTransactionInterceptor(IDbContextdbContext){_dbContext=dbContext;}publicvoidIntercept(IInvocationinvocation){usingvartransaction=_dbContext.Database.BeginTransaction();try{invocation.Proceed();transaction.Commit();}catch(Exception){transaction.Rollback();throw;}}}

4. 权限验证

我们可以使用拦截器来验证用户是否有权限执行某个方法:

publicclassAuthorizationInterceptor:IInterceptor{privatereadonlyIHttpContextAccessor_httpContextAccessor;publicAuthorizationInterceptor(IHttpContextAccessorhttpContextAccessor){_httpContextAccessor=httpContextAccessor;}publicvoidIntercept(IInvocationinvocation){varuser=_httpContextAccessor.HttpContext.User;if(!user.Identity.IsAuthenticated){thrownewUnauthorizedAccessException("用户未登录");}varrequiredRoles=invocation.Method.GetCustomAttributes<AuthorizeAttribute>().SelectMany(attr=>attr.Roles.Split(',')).ToList();if(requiredRoles.Any()&&!requiredRoles.Any(role=>user.IsInRole(role))){thrownewForbiddenAccessException("用户没有权限执行此操作");}invocation.Proceed();}}

总结

代码拦截器是一种强大的技术,允许我们在不修改原有代码的情况下,在方法执行前后插入自定义逻辑。使用 Castle.DynamicProxy,我们可以轻松实现代码拦截器,从而提高代码的可维护性和可扩展性。

在实际应用中,我们可以根据具体的需求,创建不同类型的拦截器,比如日志拦截器、性能监控拦截器、事务管理拦截器、权限验证拦截器等,从而实现各种横切关注点的分离。

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

lvgl v8版本显示二维码代码示例

效果:void lvgl_widgets_demo() {char* title (char*)"我不是萧海哇";lv_obj_t* qrcodelv_qrcode_create(lv_scr_act(),200 , lv_color_black(), lv_color_white());lv_qrcode_update(qrcode, title, strlen(title));lv_obj_align(qrcode, LV_ALIGN_CENTER, 0, 0); …

作者头像 李华
网站建设 2026/3/26 22:33:12

HashMap为什么线程不安全?底层实现原理告诉你真相

第一章&#xff1a;HashMap为什么线程不安全&#xff1f;底层实现原理告诉你真相 HashMap的底层数据结构 Java中的HashMap基于哈希表实现&#xff0c;采用“数组 链表/红黑树”的结构存储键值对。当发生哈希冲突时&#xff0c;元素会被添加到链表中&#xff1b;当链表长度超过…

作者头像 李华
网站建设 2026/4/13 0:34:46

依赖冲突频繁爆发?掌握这4种高阶策略,轻松实现项目稳定构建

第一章&#xff1a;依赖冲突频繁爆发&#xff1f;重新认识Maven的依赖解析机制 在大型Java项目中&#xff0c;依赖冲突是开发过程中最常见的痛点之一。Maven作为主流的构建工具&#xff0c;其依赖解析机制直接影响着最终打包结果的稳定性和可预测性。理解Maven如何选择和解析依…

作者头像 李华
网站建设 2026/4/5 14:14:52

【HashMap源码级剖析】:掌握put/get操作的底层执行流程

第一章&#xff1a;HashMap底层实现原理概述 HashMap 是 Java 集合框架中应用最广泛的数据结构之一&#xff0c;它基于哈希表实现键值对的存储与查找&#xff0c;提供平均时间复杂度为 O(1) 的高效访问性能。其核心机制依赖于数组、链表和红黑树的组合结构&#xff0c;在处理哈…

作者头像 李华
网站建设 2026/4/12 13:48:04

Java中如何正确判断字符串为空?99%的开发者都忽略的细节

第一章&#xff1a;Java中字符串为空判断的常见误区 在Java开发中&#xff0c;字符串为空判断是日常编码中最常见的操作之一。然而&#xff0c;许多开发者在处理这一看似简单的逻辑时&#xff0c;常常陷入误区&#xff0c;导致程序出现空指针异常&#xff08;NullPointerExcept…

作者头像 李华