.NET生态系统在短短几年内发生了翻天覆地的变化。如果你的《高级开发指南》还在引用.NET Framework时代的实践或2018年的模式,那么是时候进行一次彻底更新了。
现代.NET已经摒弃了沉重的企业级样板代码,转而拥抱云原生架构、性能优先的设计和开发效率的提升。
以下是大多数过时指南的不足之处,以及你应该采取的现代做法。
传统方式:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService) =>
_productService = productService;
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProduct(int id)
{
var product = await _productService.GetProductAsync(id);
if (product == null) return NotFound();
return Ok(product);
}
}
现代方式:
// Program.cs
app.MapGet("/api/products/{id:int}", async (int id, IProductService service) =>
await service.GetProductAsync(id) is Product product
? Results.Ok(product)
: Results.NotFound())
.WithName("GetProduct")
.WithOpenApi();
✅ 为何重要:Minimal API减少了60-70%的样板代码,提升了启动性能,非常适合微服务和无服务器应用。
传统方式:
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
// 数十行用于重写相等性方法的代码...
}
现代方式:
public record ProductDto(int Id, string Name, decimal Price);
✅ 为何重要:Record是不可变的、简洁的,并自动提供基于值的相等性判断,非常适合DTO和值对象。
传统方式:
public interface IProductRepository
{
Task<Product> GetByIdAsync(int id);
Task<IEnumerable<Product>> GetAllAsync();
Task AddAsync(Product product);
// 还有20多个方法...
}
现代方式:
public class ProductService
{
private readonly AppDbContext _context;
public ProductService(AppDbContext context) => _context = context;
public async Task<Product?> GetProductAsync(int id) =>
await _context.Products
.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == id);
}
✅ 为何重要:EF Core本身已经是一个抽象层。再用额外的仓储包装它只会增加复杂性。
传统方式:
public class ProductMapper
{
public ProductDto ToDto(Product product)
{
// 基于反射的映射
}
}
现代方式(Mapperly):
[Mapper]
public static partial class ProductMapper
{
public static partial ProductDto ToDto(Product product);
public static partial Product ToEntity(CreateProductRequest request);
}
✅ 为何重要:源生成器在编译时生成高性能代码,而基于反射的映射会拖慢性能并破坏AOT兼容性。
传统方式:
_logger.LogInformation("Processing product {ProductId}", productId);
现代方式:
builder.Services.AddHealthChecks()
.AddDbContext<AppDbContext>()
.AddRedis(connectionString);
builder.Services.AddOpenTelemetry()
.WithTracing(b => b.AddAspNetCoreInstrumentation())
.WithMetrics(b => b.AddAspNetCoreInstrumentation());
✅ 为何重要:健康检查、链路追踪和结构化日志在分布式系统中不再是可选项,而是必需品。
传统方式:
public class EmailSettings
{
public string SmtpServer { get; set; }
public string ApiKey { get; set; } // 密钥明文存储在配置中
}
现代方式:
builder.Services.AddOptions<EmailSettings>()
.Bind(builder.Configuration.GetSection("Email"))
.ValidateOnStart();
builder.Configuration.AddAzureKeyVault(keyVaultUri, credential);
✅ 为何重要:密钥应存储在安全的存储中,而不是appsettings.json。启动时验证可避免生产环境中的意外问题。
传统方式:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
现代方式:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = builder.Configuration["Auth:Authority"];
options.Audience = builder.Configuration["Auth:Audience"];
});
✅ 为何重要:Cookie适用于Web应用,而不适用于API。基于令牌的身份验证是安全、可扩展API的标准。
传统方式:
public ProductDto GetProduct(int id) =>
_productService.GetProductAsync(id).Result; // 可能导致死锁
现代方式:
public async Task<ProductDto?> GetProductAsync(int id) =>
await _productService.GetProductAsync(id);
✅ 为何重要:阻塞异步调用会导致死锁。但并非所有地方都需要异步,仅在发生I/O操作时使用。
这些不仅仅是语法升级,它们代表了一种思维方式的转变: