5个鲜为人知的C#/.NET开发秘籍:从时间处理到安全配置的实战技巧

作者:微信公众号:【架构师老卢】
6-7 8:33
14

欢迎来到新一期的5个C#和.NET开发技巧!抱歉过去两个月断更——上次更新还是在二月份——这段时间确实忙得不可开交,而且撰写这些技术文章总比预期耗时更长。

本期内容包含:避免直接使用DateTime.Now、Entity Framework Core的全局查询过滤器、并发集合、用户密钥管理、Base64Url编码技巧。

每个开发者都有独特的编程风格,这很好。但我们都会掌握一些他人可能不知道的技巧。本文我将分享个人最常用的5个C#/.NET开发秘籍。有些你可能熟悉,有些或许陌生,也可能某些并不适用于你的场景。

这些技巧的呈现方式不会长篇大论,而是通过简明描述和示例代码展示核心思想。如果对任何技巧有疑问,欢迎在评论区留言。若某主题需求旺盛,我会专门为它撰写完整文章。

示例代码基础

本文大部分示例基于以下类定义、枚举和列表:

public class Product
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public int Stock { get; set; }
    public Status Status { get; set; }
    public bool Available { get; set; }
}

public enum Status
{
    Ordered,
    Delivered,
    Delayed,
    Unknown
}

List<Product> products = 
[
    new() { Id = 1, Title = "7Up", Status = Status.Ordered, Stock = 10, Available = true },
    new() { Id = 2, Title = "Chips", Status = Status.Ordered, Stock = 0, Available = true },
    // 其他产品数据...
];

技巧1:避免直接使用DateTime.Now

(适用版本:.NET 1+)

这个标题可能有些绝对,但为了简洁我保留了它。大多数开发者会直接用DateTime.Now获取当前时间——这本就是它的设计目的,不是吗?但它存在一些可能引发重大问题的缺陷:

  • 受服务器时区影响,当不同时区客户端共用数据库时会导致时间数据不可靠
  • 难以在单元测试中模拟,导致测试结果不稳定

解决方案是使用DateTimeOffset.UtcNow

var timestamp = DateTime.Now; // 能用但不推荐

// 替代方案
var timestamp = DateTimeOffset.UtcNow; // 更优选择

为了支持单元测试,可以创建返回DateTimeOffset的接口,在需要时注入依赖:

public interface IDateTimeProvider
{
    DateTimeOffset GetCurrentTime();
}

// 生产环境实现
public class DateTimeProvider : IDateTimeProvider
{
    public DateTimeOffset GetCurrentTime() => DateTimeOffset.UtcNow;
}

// 测试环境可模拟实现

技巧2:EF Core全局查询过滤器

(适用版本:Entity Framework Core)

当需要频繁对某实体应用相同查询条件时(比如99%的场景只需要查询可用商品),EF Core的全局查询过滤器能消除重复代码。以下是不使用过滤器的常规做法:

using (var context = new ProductsContext())
{
    var availableProducts = context.Products
        .Where(x => x.Available)
        .ToList();
}

在DbContext的OnModelCreating方法中配置全局过滤器:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .HasQueryFilter(x => x.Available);
}

之后所有查询都会自动应用该条件。如需临时禁用,使用IgnoreQueryFilters()

var allProducts = context.Products
    .IgnoreQueryFilters()
    .ToList();

技巧3:并发集合的使用

(适用版本:.NET Framework 4+)

标准集合类型(如List)非线程安全,多线程操作时需要手动加锁。并发集合(如ConcurrentDictionary)内置线程安全机制:

var concurrentDict = new ConcurrentDictionary<int, Product>();

Parallel.ForEach(products, product =>
{
    concurrentDict.TryAdd(product.Id, product);
});

if (concurrentDict.TryGetValue(1, out var foundProduct))
    Console.WriteLine($"找到产品:{foundProduct.Title}");

注意

  • 在单线程场景可能有轻微性能损耗
  • ConcurrentBag等类型不保证元素顺序

技巧4:用户密钥管理

(适用版本:Visual Studio 2015, .NET Core 1+)

敏感信息不应存储在appsettings.json中。Visual Studio的"管理用户密钥"功能可将开发环境密钥存储在用户个人目录:

  1. 右键项目 → 选择"管理用户密钥"
  2. 首次使用会生成secrets.json文件(路径:%APPDATA%\microsoft\UserSecrets\<GUID>\
  3. 添加密钥:
{
  "Products": {
    "ConnectionString": "你的连接字符串"
  }
}

通过配置系统读取:

var config = new ConfigurationBuilder()
    .AddUserSecrets<Program>()
    .Build();

Console.WriteLine(config["Products:ConnectionString"]);

生产环境推荐使用Azure Key Vault或AWS Secrets Manager。

技巧5:Base64Url编码助手

(适用版本:.NET 9)

传统Base64编码会产生URL不友好字符(+/=)。.NET 9新增的Base64Url工具类:

var bytes = Encoding.UTF8.GetBytes("Coffee with milk");
var standardBase64 = Convert.ToBase64String(bytes); // 含特殊字符
var urlSafe = Base64Url.EncodeToString(bytes); // URL友好格式

以上就是本期的5个C#/.NET开发技巧。无论这些技巧对你来说是新知还是旧识,希望都能有所启发。如果你有独家技巧想要分享,欢迎在评论区留言——它们可能会出现在下期内容中!

相关留言评论
昵称:
邮箱:
阅读排行