我构建.NET系统已有17年以上——从初创公司到企业级应用,再到复杂的单体系统。这里有一个残酷的事实:
"我们遇到的大部分代码问题并非源于.NET本身...而是因为我们没有正确使用合适的工具。"
自然流畅的验证代码,编写、阅读和维护都变得轻松。
public class OrderValidator : AbstractValidator<Order>
{
public OrderValidator()
{
RuleFor(x => x.Amount).GreaterThan(0).WithMessage("金额必须为正数");
RuleFor(x => x.CustomerEmail).NotEmpty().EmailAddress();
RuleFor(x => x.OrderDate).LessThanOrEqualTo(DateTime.UtcNow).WithMessage("不允许未来日期的订单");
}
}
我为什么爱它:
📌 适用场景:当你的模型包含10+验证规则时
⚠️ 不适用场景:在紧密循环中需要超低延迟性能时
var dto = user.Adapt<UserDto>();
一行代码。零配置。闪电般快速。
我为什么爱它:
Adapt<T>()
实现零配置映射📌 适用场景:当你在10+个DTO和领域实体间映射,想要干净快速的转换而不需要臃肿的配置时
var result = await Policy
.Handle<HttpRequestException>()
.RetryAsync(3)
.ExecuteAsync(() => _httpClient.GetAsync(url));
一行代码将脆弱的HTTP调用变成经过战斗考验的战士。
我为什么爱它:一行代码实现弹性——重试、断路器、超时、回退
💡 使用案例:带随机退避的重试
var retryPolicy = Policy
.Handle<HttpRequestException>()
.WaitAndRetryAsync(
3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(Random.Shared.Next(0, 100)),
onRetry: (exception, timeSpan, retryCount, context) =>
{
_logger.LogWarning($"第{retryCount}次重试,等待{timeSpan.TotalSeconds}秒,原因:{exception.Message}");
});
var response = await retryPolicy.ExecuteAsync(() => _httpClient.GetAsync("https://api.example.com/data"));
📌 适用场景:当你调用容易出现问题的第三方服务或内部微服务时
仅用接口自动生成REST客户端
public interface IMyApi
{
[Get("/users/{id}")]
Task<User> GetUserAsync(int id);
}
var api = RestService.For<IMyApi>("https://api.example.com");
我为什么爱它:
🔍 示例用例:简洁调用外部API
public interface IGitHubApi
{
[Get("/users/{username}")]
Task<GitHubUser> GetUser(string username);
}
var client = RestService.For<IGitHubApi>("https://api.github.com");
var user = await client.GetUser("dotnet");
Console.WriteLine(user.Name);
无需手动编写HTTP头、解析JSON或处理状态码。
📌 适用场景:当你需要消费2+个REST API并希望减少模板代码、提高生产力时
public record GetUserQuery(int Id) : IRequest<User>;
public class GetUserHandler : IRequestHandler<GetUserQuery, User>
{
public Task<User> Handle(GetUserQuery request, CancellationToken ct)
=> _userService.GetByIdAsync(request.Id);
}
我为什么爱它:促进垂直切片架构、关注点分离和基于处理器的可测试性
🔍 示例用例:模块化用户查询和命令
public record UpdateUserCommand(int Id, string Email) : IRequest;
public class UpdateUserHandler : IRequestHandler<UpdateUserCommand>
{
public async Task Handle(UpdateUserCommand cmd, CancellationToken ct)
{
var user = await _db.Users.FindAsync(cmd.Id);
user.Email = cmd.Email;
await _db.SaveChangesAsync();
}
}
现在你的更新逻辑存在于UpdateUserCommand中,而不是深埋在UserService的6个不相关方法下。
📌 适用场景:当你厌倦了上帝服务并想要真正的关注点分离,或实现CQRS时
var faker = new Faker<User>()
.RuleFor(u => u.Name, f => f.Name.FullName())
.RuleFor(u => u.Email, f => f.Internet.Email());
我为什么爱它:加速测试、填充开发数据库、无需真实用户即可进行压力测试
🔍 示例用例:为负载测试生成1000个假用户
var users = new Faker<User>()
.RuleFor(u => u.Id, f => Guid.NewGuid())
.RuleFor(u => u.Name, f => f.Name.FullName())
.RuleFor(u => u.Email, f => f.Internet.Email())
.Generate(1000);
将其导入你的EF Core种子数据或MongoDB插入——瞬间就能获得填充好的测试数据库。
📌 适用场景:编写单元测试、集成测试或填充开发环境时
像单元测试一样的性能分析
[Benchmark]
public void ParseWithSpan()
{
var value = int.Parse("123");
}
普通开发者靠猜测。优秀开发者靠测量。
我为什么爱它:
🔍 示例用例:比较3种数字解析方法
[MemoryDiagnoser]
public class ParsingBenchmarks
{
[Benchmark]
public int ParseInt() => int.Parse("123");
[Benchmark]
public int ConvertInt() => Convert.ToInt32("123");
[Benchmark]
public int TryParseInt()
{
int.TryParse("123", out var result);
return result;
}
}
运行后,BenchmarkDotNet会给你并列对比: