如何从Razor调用需DbContext的通用键值缓存读取例程?
嘿,这个问题我之前帮不少开发者捋清楚过——静态类没法用依赖注入确实挺挠头的,尤其是还要在Razor里调用涉及DbContext的逻辑。下面给你几个更优的实现思路,按推荐程度排序:
最优方案:重构为依赖注入友好的服务类
首先,静态类本身就和ASP.NET Core的依赖注入理念相悖,所以最推荐的做法是把Resources里的静态逻辑重构为一个可注入的服务:
- 定义服务接口,明确功能契约:
public interface IResourceService { Task<string> GetConfigDisplayAsync(string key); }
- 实现服务类,注入所需依赖(缓存和DbContext):
public class ResourceService : IResourceService { private readonly IMemoryCache _cache; private readonly YourDbContext _dbContext; public ResourceService(IMemoryCache cache, YourDbContext dbContext) { _cache = cache; _dbContext = dbContext; } public async Task<string> GetConfigDisplayAsync(string key) { // 优先从缓存读取 if (_cache.TryGetValue(key, out string value)) { return value; } // 缓存无数据时,从数据库查询 var config = await _dbContext.Configs.FirstOrDefaultAsync(c => c.Key == key); value = config?.DisplayValue ?? string.Empty; // 将结果写入缓存,设置合理过期时间 _cache.Set(key, value, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }); return value; } }
- 在
Program.cs中注册服务:
builder.Services.AddScoped<IResourceService, ResourceService>();
- 在Razor页面/视图中注入并使用:
@inject IResourceService ResourceService @{ var displayValue = await ResourceService.GetConfigDisplayAsync("your-target-key"); } <p>配置显示值:@displayValue</p>
这个方案完全贴合ASP.NET Core的设计规范,依赖关系清晰,易于单元测试(可以轻松Mock缓存和DbContext),也没有静态状态带来的并发风险,是长期维护的最佳选择。
兼容旧代码:静态类注入服务实例(谨慎使用)
如果因为历史遗留问题必须保留静态类,可以在应用启动时把所需服务实例注入到静态类的静态属性中:
- 修改
Resources类,添加初始化逻辑:
public static class Resources { private static IMemoryCache _cache; private static YourDbContext _dbContext; // 在应用启动时调用,初始化静态依赖 public static void Initialize(IMemoryCache cache, YourDbContext dbContext) { _cache = cache; _dbContext = dbContext; } public static async Task<string> ConfigDisplay(string key) { if (_cache == null || _dbContext == null) { throw new InvalidOperationException("Resources类未完成初始化,请先调用Initialize方法"); } // 缓存查询与数据库读取逻辑同服务类示例 if (_cache.TryGetValue(key, out string value)) { return value; } var config = await _dbContext.Configs.FirstOrDefaultAsync(c => c.Key == key); value = config?.DisplayValue ?? string.Empty; _cache.Set(key, value, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }); return value; } }
- 在
Program.cs中完成静态类初始化:
var app = builder.Build(); // 创建服务作用域,获取所需服务实例 using var scope = app.Services.CreateScope(); var cache = scope.ServiceProvider.GetRequiredService<IMemoryCache>(); var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>(); Resources.Initialize(cache, dbContext); // 后续启动逻辑 app.Run();
- 在Razor中直接调用静态方法:
@{ var displayValue = await Resources.ConfigDisplay("your-target-key"); } <p>配置显示值:@displayValue</p>
⚠️ 注意:这个方式存在线程安全隐患,而且静态状态会导致单元测试难度上升(每次测试前都需要重新初始化),仅适合临时兼容旧代码,不推荐作为长期方案。
临时解决:Razor中传递服务给静态方法
如果不想重构也不想初始化静态类,还可以在Razor里获取服务实例,直接传递给静态方法:
- 修改静态方法,接收依赖参数:
public static class Resources { public static async Task<string> ConfigDisplay(string key, IMemoryCache cache, YourDbContext dbContext) { // 缓存查询与数据库读取逻辑同前 if (cache.TryGetValue(key, out string value)) { return value; } var config = await dbContext.Configs.FirstOrDefaultAsync(c => c.Key == key); value = config?.DisplayValue ?? string.Empty; cache.Set(key, value, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }); return value; } }
- 在Razor中注入服务并调用:
@inject IMemoryCache Cache @inject YourDbContext DbContext @{ var displayValue = await Resources.ConfigDisplay("your-target-key", Cache, DbContext); } <p>配置显示值:@displayValue</p>
这个方式比硬编码获取服务要好,但代码冗余度高,每次调用都要传递依赖,仅适合短期临时解决。
内容的提问来源于stack exchange,提问作者ScottG
相关产品推荐
相关产品推荐

