You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Razor调用需DbContext的通用键值缓存读取例程?

嘿,这个问题我之前帮不少开发者捋清楚过——静态类没法用依赖注入确实挺挠头的,尤其是还要在Razor里调用涉及DbContext的逻辑。下面给你几个更优的实现思路,按推荐程度排序:

最优方案:重构为依赖注入友好的服务类

首先,静态类本身就和ASP.NET Core的依赖注入理念相悖,所以最推荐的做法是把Resources里的静态逻辑重构为一个可注入的服务:

  1. 定义服务接口,明确功能契约:
public interface IResourceService
{
    Task<string> GetConfigDisplayAsync(string key);
}
  1. 实现服务类,注入所需依赖(缓存和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;
    }
}
  1. 在Program.cs中注册服务:
builder.Services.AddScoped<IResourceService, ResourceService>();
  1. 在Razor页面/视图中注入并使用:
@inject IResourceService ResourceService

@{
    var displayValue = await ResourceService.GetConfigDisplayAsync("your-target-key");
}

<p>配置显示值:@displayValue</p>

这个方案完全贴合ASP.NET Core的设计规范,依赖关系清晰,易于单元测试(可以轻松Mock缓存和DbContext),也没有静态状态带来的并发风险,是长期维护的最佳选择。

兼容旧代码:静态类注入服务实例(谨慎使用)

如果因为历史遗留问题必须保留静态类,可以在应用启动时把所需服务实例注入到静态类的静态属性中:

  1. 修改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;
    }
}
  1. 在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();
  1. 在Razor中直接调用静态方法:
@{
    var displayValue = await Resources.ConfigDisplay("your-target-key");
}

<p>配置显示值:@displayValue</p>

⚠️ 注意:这个方式存在线程安全隐患,而且静态状态会导致单元测试难度上升(每次测试前都需要重新初始化),仅适合临时兼容旧代码,不推荐作为长期方案。

临时解决:Razor中传递服务给静态方法

如果不想重构也不想初始化静态类,还可以在Razor里获取服务实例,直接传递给静态方法:

  1. 修改静态方法,接收依赖参数:
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;
    }
}
  1. 在Razor中注入服务并调用:
@inject IMemoryCache Cache
@inject YourDbContext DbContext

@{
    var displayValue = await Resources.ConfigDisplay("your-target-key", Cache, DbContext);
}

<p>配置显示值:@displayValue</p>

这个方式比硬编码获取服务要好,但代码冗余度高,每次调用都要传递依赖,仅适合短期临时解决。

内容的提问来源于stack exchange,提问作者ScottG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:47:20