发布于2026-07-23 阅读(0)
扫一扫,手机访问
先从最基础的静态类说起吧。很多开发者最初接触全局数据,都是从静态类开始的——一个静态类,几个静态属性或字段,数据就这么“全局”了。
public static class GlobalData{ public static string ApplicationName { get; set; } = "MyApp"; public static int MaxConnections { get; } = 100; private static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); public static void SetCache(string key, object value) { _cache[key] = value; } public static T GetCache(string key) { return _cache.TryGetValue(key, out var value) ? (T)value : default; }}
特点
ConcurrentDictionary,但如果是普通的 Dictionary,就需要自行加锁优缺点
说到配置,.NET 提供了两种主流方式:一种是 ASP.NET Core 的 appsettings.json,另一种是 WinForms/WPF 的用户设置。先看前者。
1. appsettings.json (ASP.NET Core)
{ "AppConfig": { "Theme": "Dark", "Timeout": 30 }}
使用方式:
// 在Startup中配置services.Configure(Configuration.GetSection("AppConfig"));// 注入使用public class MyService{ private readonly AppConfig _config; public MyService(IOptions config) { _config = config.Value; }}
2. 用户设置 (WinForms/WPF)
// 保存设置Properties.Settings.Default.Theme = "Dark";Properties.Settings.Default.Sa ve();// 读取设置var theme = Properties.Settings.Default.Theme;
特点
在 ASP.NET Core 时代,依赖注入已经成为了标配。它不仅仅是解耦服务的工具,更是管理全局服务生命周期的利器。
// 注册服务services.AddSingleton();services.AddScoped ();// 使用public class MyController : Controller{ private readonly IGlobalCache _cache; public MyController(IGlobalCache cache) { _cache = cache; }}
特点
生命周期有三种:
线程安全:取决于你的实现——如果用 Singleton 服务存了可变状态,那就得小心并发问题。
适用场景:ASP.NET Core 应用、需要共享的服务实例。
如果只是临时存一些高频访问的小数据,内存缓存是首选。
// 注册services.AddMemoryCache();// 使用public class DataService{ private readonly IMemoryCache _cache; public DataService(IMemoryCache cache) { _cache = cache; } public string GetCachedData(string key) { return _cache.GetOrCreate(key, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30); return ExpensiveDatabaseCall(); }); }}
特点
当你的应用扩展到多台服务器时,每个实例各自的内存缓存就不灵了。分布式缓存就是为了解决跨进程、跨服务器数据共享的问题。
// 使用Redisservices.AddStackExchangeRedisCache(options =>{ options.Configuration = "localhost:6379";});// 使用public async Task GetCachedDataAsync(string key){ return await _distributedCache.GetAsync(key);}
特点
这是一个轻量级的请求级数据容器,特别适合在中间件和控制器之间传递临时数据。
// 中间件中设置app.Use(async (context, next) =>{ context.Items["RequestStartTime"] = DateTime.UtcNow; await next();});// 控制器中访问var startTime = HttpContext.Items["RequestStartTime"] as DateTime?;
特点
环境变量是跨平台部署时最常用的配置方式,特别是在容器化和云环境中。
var envVar = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
特点
对于那些需要持久化、需要管理、需要版本控制的全局配置,数据库存储是最可靠的方案。
// 使用EF Corepublic class AppDbContext : DbContext{ public DbSet GlobalSettings { get; set; }}// 使用var setting = await _dbContext.GlobalSettings .FirstOrDefaultAsync(s => s.Key == "MaintenanceMode");
特点
这么多方式,到底该选哪个?下面这张表可以帮助你快速决策:
| 存储方式 | 生命周期 | 持久化 | 分布式支持 | 典型使用场景 |
|---|---|---|---|---|
| 静态成员 | 应用程序域 | 否 | 否 | 全局常量、简单缓存 |
| 应用程序配置 | 持久化 | 是 | 部分 | 应用设置、用户偏好 |
| 依赖注入容器 | 取决于注册类型 | 否 | 否 | 服务共享、全局服务 |
| 内存缓存 | 应用程序 | 否 | 否 | 频繁访问的临时数据 |
| 分布式缓存 | 持久化 | 是 | 是 | 多实例共享数据 |
| HttpContext.Items | 请求期间 | 否 | 否 | 请求级数据传递 |
| 环境变量 | 进程/系统 | 是 | 是 | 部署配置、环境特定设置 |
| 数据库存储 | 持久化 | 是 | 是 | 需要持久化的全局配置 |
综合以上,几个需要记住的原则:
1. 按需选择:别一上来就上 Redis。先看数据特性——大小、访问频率、生命周期,再决定用什么。高频小数据用内存缓存,配置数据用 appsettings.json,用户数据用数据库,这是基本的分层思路。
2. 分层设计:
3. 线程安全:多线程访问时,要么用 ConcurrentDictionary 这类线程安全集合,要么用 Immutable 集合防止意外修改。
4. 性能考虑:大数据集别用静态变量,它一直占着内存不释放。缓存要设置过期策略,否则内存会越来越高。
5. 测试友好:静态类写起来爽,但测试起来痛苦。能通过依赖注入管理全局服务,就尽量别用静态类。
6. 分布式场景:多个服务器实例时,不要依赖本地缓存共享 Session 或状态,用分布式缓存或消息队列来同步。
在实际项目中,很多时候你会同时用内存缓存和分布式缓存。思路很简单:本地内存缓存扛高频访问,分布式缓存做跨进程共享和持久化。下面是一个典型的混合缓存实现:
public class HybridCache{ private readonly IMemoryCache _memoryCache; private readonly IDistributedCache _distributedCache; public HybridCache(IMemoryCache memoryCache, IDistributedCache distributedCache) { _memoryCache = memoryCache; _distributedCache = distributedCache; } public async Task GetOrCreateAsync(string key, Func> factory, TimeSpan expiration) { // 先从本地缓存查 if (_memoryCache.TryGetValue(key, out T memoryValue)) { return memoryValue; } // 本地没有,查分布式缓存 var distributedValue = await _distributedCache.GetStringAsync(key); if (distributedValue != null) { var value = JsonSerializer.Deserialize(distributedValue); _memoryCache.Set(key, value, expiration); // 回填本地缓存 return value; } // 都没有,执行工厂方法获取新数据 var newValue = await factory(); _memoryCache.Set(key, newValue, expiration); await _distributedCache.SetStringAsync(key, JsonSerializer.Serialize(newValue), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration }); return newValue; }}
另一个常见需求是配置热重载——不改代码、不重启应用,直接修改配置文件就能生效。依赖注入结合 IOptionsMonitor 可以优雅地实现:
// Program.csbuilder.Services.Configure(builder.Configuration.GetSection("AppConfig"));builder.Services.AddSingleton >(provider => provider.GetRequiredService >());// 使用public class ConfigService{ private readonly AppConfig _config; public ConfigService(IOptionsMonitor configMonitor) { _config = configMonitor.CurrentValue; configMonitor.OnChange(newConfig => { _config = newConfig; }); }}
通过合理选择和组合这些全局数据存储方式,你可以构建出既高效又易于维护的 .NET 应用程序架构。没有银弹,但理解每种方案的优缺点和适用场景,就已经赢了一半。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8