在 .NET Core 的开发体系中,特性(Attribute)不仅仅是一个简单的标签,更是实现声明式编程、解耦业务逻辑与基础设施代码的核心机制。无论是数据验证、API 路由控制,还是复杂的面向切面编程(AOP),特性都提供了高效的解决方案。
1. 特性 Attribute
特性
从本质上讲,特性是一种将元数据(Metadata)附加到代码元素(如类、方法、属性、参数等)上的机制。它不会直接改变代码的执行逻辑,而是为编译器或运行时提供额外的描述性信息。
理解为给代码打的"标签"或"注解"。例如:
[Required]告诉框架该字段不能为空。[HttpGet]告诉 ASP.NET Core 该方法仅响应 GET 请求。[Serializable]告诉序列化器该对象可以被序列化。
在没有引入特性之前,开发者往往需要通过大量的 if-else 或 switch 语句来处理诸如数据库映射、JSON 序列化、数据验证等逻辑。这导致代码紧密耦合,维护困难。
引入特性后,实现了声明式编程的优势:
- 解耦:业务代码专注于核心逻辑,横切关注点(如日志、验证、权限)通过特性分离。
- 统一规则:框架通过扫描特性自动执行相应逻辑,确保行为一致。
- **简洁性无需编写繁琐的基础设施代码,只需添加标签即可生效。
2.自定义特性
虽然 .NET 提供了丰富的内置特性,但在实际开发中,我们常需要根据业务需求创建自定义特性例如实现特定的日志记录、权限校验或缓存策略。
创建自定义特性通常遵循以下步骤:
- 创建一个继承自
System.Attribute的类。 - 使用
AttributeUsage指定特性的适用目标(类、方法、属性等)。 - 定义构造函数和属性以传递参数。
自定义日志特性
需要一个特性,用于标记需要记录详细执行日志的方法。
cs
using System;
// 1. 定义特性类
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class CustomLogAttribute : Attribute
{
public string Message { get; set; }
public LogLevel Level { get; set; } = LogLevel.Information;
public CustomLogAttribute(string message)
{
Message = message;
}
}
public enum LogLevel
{
Information,
Warning,
Error
}
使用自定义特性
cs
public class OrderService
{
// 2. 应用特性
[CustomLog("开始处理订单创建", Level = LogLevel.Information)]
public void CreateOrder(Order order)
{
// 业务逻辑
Console.WriteLine($"Order {order.Id} created.");
}
}
此时,CustomLogAttribute 仅仅是一个元数据标记。若要使其真正生效(即执行日志记录逻辑),通常需要结合反射 或AOP拦截器。
3.扩展 AOP 应用
特性本身不执行代码,必须配合拦截机制才能实现面向切面编程(AOP)。在 .NET Core 中,实现 AOP 的主流方式包括使用动态代理库(如 Castle DynamicProxy)或依赖注入容器的拦截扩展(如 Autofac)。
AOP 的核心思想
AOP旨在将横切关注点(如日志、事务、异常处理)从业务逻辑中剥离。当调用被特性标记的方法时,流程如下:
- 调用方触发方法。
- 代理对象拦截调用。
- 执行前置逻辑(如记录开始时间、检查权限)。
- 执行真实业务方法。
- 执行后置逻辑(如记录结束时间、捕获异常)。
结合 Castle DynamicProxy 实现日志拦截
以下示例展示如何通过实现 `IInterceptor接口,读取自定义特性并执行日志记录。
定义拦截器
cs
using Castle.DynamicProxy;
using System.Reflection;
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// 1. 获取方法上的自定义特性
var method = invocation.MethodInvocationTarget;
var logAttribute = method.GetCustomAttributes(typeof(CustomLogAttribute), true)
.FirstOrDefault() as CustomLogAttribute;
if (logAttribute != null)
{
// 2. 前置逻辑:记录开始
Console.WriteLine($"[LOG] {logAttribute.Message} - Start");
}
try
{
// 3. 执行真实方法
invocation.Proceed();
}
catch (Exception ex)
{
// 4. 异常处理
Console.WriteLine($"[ERROR] Exception occurred: {ex.Message}");
throw;
}
finally
{
if (logAttribute != null)
{
// 5. 后置逻辑:记录结束
Console.WriteLine($"[LOG] {logAttribute.Message} - End");
}
}
}
}
创建代理并执行
cs
var proxyGenerator = new ProxyGenerator();
var interceptor = new LogInterceptor();
// 创建 OrderService 的代理对象
var orderService = proxyGenerator.CreateClassProxy<OrderService>(interceptor);
var order = new Order { Id = 1001 };
orderService.CreateOrder(order);
// 输出结果:
// [LOG] 开始处理订单创建 - Start
// Order 1001 created.
// [LOG] 开始处理订单创建 - End
- Autofac + Castle DynamicProxy:在 ASP.NET Core 项目中,常替换默认 DI 容器为 Autofac,利用其 EnableInterfaceInterceptors 或 EnableClassInterceptors 功能,自动为注册的服务生成代理,无需手动创建 ProxyGenerator。
- DispatchProxy:.NET Core 内置的轻量级代理类,适用于简单的场景,但功能不如 Castle DynamicProxy 强大。
4.常用内置特性分类
.NET Core 框架内置了大量特性,覆盖了 Web 开发、数据验证、依赖注入等多个领域。熟练掌握这些特性能极大提升开发效率。
API 与 MVC 控制
这些特性主要用于 ASP.NET Core Web API 和 MVC 控制器,定义路由、HTTP 方法和行为。
| 特性 | 说明 | 示例 |
|---|---|---|
[ApiController] |
标记控制器为 API 风格,启用自动模型验证和错误响应。 | [ApiController] |
[Route] |
定义路由模板。 | [Route("api/[controller]")] |
[HttpGet] / [HttpPost] |
指定允许的 HTTP 谓词。 | [HttpGet("{id}")] |
[FromBody] |
指示参数从请求正文中绑定。 | public IActionResult Post([FromBody] User user) |
[FromQuery] |
指示参数从查询字符串中绑定。 | public IActionResult Get([FromQuery] int page) |
数据验证特性
主要用于 DTO(数据传输对象)或实体模型,配合模型验证中间件使用。
| 特性 | 说明 | 示例 |
|---|---|---|
[Required] |
字段不能为 null 或空。 | [Required(ErrorMessage = "姓名必填")] |
[StringLength] |
限制字符串长度。 | [StringLength(100)] |
[Range] |
限制数值范围。 | [Range(1, 120)] |
[EmailAddress] |
验证邮箱格式。 | [EmailAddress] |
[RegularExpression] |
使用正则表达式验证。 | [RegularExpression(@"^\d+$")] |
数据实体特性 (Entity Framework Core)
用于配置数据库映射关系。
| 特性 | 说明 | 示例 |
|---|---|---|
[Key] |
指定主键。 | [Key] |
[Table] |
指定对应的数据库表名。 | [Table("Users")] |
[Column] |
指定列名或类型。 | [Column("user_name")] |
[NotMapped] |
排除属性,不映射到数据库。 | [NotMapped] |
[DatabaseGenerated] |
指定数据库生成策略(如自增)。 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] |
依赖注入与服务生命周期
引入了直接标记服务生命周期的特性,简化了注册过程。
| 特性 | 说明 |
|---|---|
[ServiceLifetime.Scoped] |
标记服务为 Scoped 生命周期。 |
[ServiceLifetime.Singleton] |
标记服务为 Singleton 生命周期。 |
[ServiceLifetime.Transient] |
标记服务为 Transient 生命周期。 |
PS:使用这些特性时,通常需要在程序启动时扫描程序集并自动注册服务。
安全与授权
| 特性 | 说明 |
|---|---|
[Authorize] |
要求用户经过身份验证才能访问。 |
[AllowAnonymous] |
允许匿名访问,通常用于覆盖全局授权策略。 |
[ValidateAntiForgeryToken] |
防止跨站请求伪造攻击。 |
总结
特性(Attribute)是 .NET Core 生态中连接元数据与运行时行为的桥梁。
- 理解本质:特性是元数据,需配合反射或拦截器才能产生实际效果。
- 自定义扩展 :通过继承
Attribute类,可以轻松扩展业务所需的标记能力。 - AOP 实战:结合 Castle DynamicProxy 或 Autofac,利用特性实现日志、事务、权限等横切逻辑的自动化处理,显著提升代码的可维护性。
- 善用内置:熟练掌握系统内置的特性,能够以更少的代码实现标准化的 Web 开发、数据验证和 ORM 映射。