现代.NET开发八大最佳实践:让你的代码更高效、更云原生

作者:微信公众号:【架构师老卢】
9-19 6:35
9

.NET生态系统在短短几年内发生了翻天覆地的变化。如果你的《高级开发指南》还在引用.NET Framework时代的实践或2018年的模式,那么是时候进行一次彻底更新了。

现代.NET已经摒弃了沉重的企业级样板代码,转而拥抱云原生架构、性能优先的设计和开发效率的提升。

以下是大多数过时指南的不足之处,以及你应该采取的现代做法。


1. 用Minimal API替代重型控制器

传统方式

[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%的样板代码,提升了启动性能,非常适合微服务和无服务器应用。


2. 优先使用Record替代冗长的DTO

传统方式

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和值对象。


3. 停止过度使用仓储模式

传统方式

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本身已经是一个抽象层。再用额外的仓储包装它只会增加复杂性。


4. 用源生成器替代反射

传统方式

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兼容性。


5. 思考可观测性,而不仅仅是日志记录

传统方式

_logger.LogInformation("Processing product {ProductId}", productId);

现代方式

builder.Services.AddHealthChecks()
    .AddDbContext<AppDbContext>()
    .AddRedis(connectionString);

builder.Services.AddOpenTelemetry()
    .WithTracing(b => b.AddAspNetCoreInstrumentation())
    .WithMetrics(b => b.AddAspNetCoreInstrumentation());

为何重要:健康检查、链路追踪和结构化日志在分布式系统中不再是可选项,而是必需品。


6. 使用为云原生设计的配置模式

传统方式

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。启动时验证可避免生产环境中的意外问题。


7. 现代化身份验证方式

传统方式

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的标准。


8. 在真正需要的地方使用Async/Await

传统方式

public ProductDto GetProduct(int id) =>
    _productService.GetProductAsync(id).Result; // 可能导致死锁

现代方式

public async Task<ProductDto?> GetProductAsync(int id) =>
    await _productService.GetProductAsync(id);

为何重要:阻塞异步调用会导致死锁。但并非所有地方都需要异步,仅在发生I/O操作时使用。


这对你的团队意味着什么?

这些不仅仅是语法升级,它们代表了一种思维方式的转变:

  • 性能优先:减少内存和CPU开销
  • 云原生:为容器和分布式系统构建
  • 开发体验:减少样板代码,聚焦业务逻辑
  • 可观测性:从第一天起就为监控和诊断设计

高级开发者的行动项

  1. 审查你的指南:找出仍在使用的过时模式。
  2. 先在新项目中应用变更:不要一次性重构所有内容。
  3. 逐步重构:分步演进旧代码库。
  4. 培训团队:解释“为什么”,而不仅仅是“是什么”。
  5. 采用现代工具:分析器、源生成器、OpenTelemetry。
相关留言评论
昵称:
邮箱:
阅读排行