ASP.NET Core 2.0中的应用程序变量

21

我该如何在ASP.NET Core 2.0中设置和访问应用程序范围的变量?

细节:我有一个变量,我们称之为CompanyName,它驻留在数据库中,并在每个页面上使用。 我不想每次显示CompanyName时都访问数据库。 在100年前,我会设置 Application["CompanyName']=CompanyName,但我理解在.NET Core中这不是正确的做法。那么应该使用什么替代方法呢?


你的应用程序中是否有其他会话上下文,例如用户/租户/授权声明或其他配置文件信息,该变量所属或可能同时检索到?在这种情况下,您可以调用它。或者使用某种带缓存的数据调用/检索? - Mark Redman
2个回答

23

在过去的100年里,有很多进展。我相信在ASP.NET 1.0时期,ASP Classic中的Application对象被(缓存)所取代(尽管为了向后兼容性而保留了Application对象)。

AspNetCore已经替换了ASP.NET的缓存机制并使其支持DI,但它仍然非常类似于ASP.NET中的状态。主要的区别是现在需要注入它,而不再使用静态的HttpContext.Current.Cache属性。

在启动时注册缓存...

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMemoryCache();
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvcWithDefaultRoute();
    }
}

你可以像这样注入它...

public class HomeController : Controller
{
    private IMemoryCache _cache;

    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

    public IActionResult Index()
    {
        string companyName = _cache[CacheKeys.CompanyName] as string;

        return View();
    }

为了使其在整个应用程序中起作用,您可以使用过滤器中间件与某种缓存刷新模式相结合:

  1. 尝试从缓存中获取值
  2. 如果尝试失败
    • 从数据库中查找数据
    • 重新填充缓存
  3. 返回值

public string GetCompanyName()
{
    string result;

    // Look for cache key.
    if (!_cache.TryGetValue(CacheKeys.CompanyName, out result))
    {
        // Key not in cache, so get data.
        result = // Lookup data from db

        // Set cache options.
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Keep in cache for this time, reset time if accessed.
            .SetSlidingExpiration(TimeSpan.FromMinutes(60));

        // Save data in cache.
        _cache.Set(CacheKeys.CompanyName, result, cacheEntryOptions);
    }

    return result;
}

当然,你可以清理一下,创建一个带有强类型属性的服务,作为包装器注入到控制器中的缓存中,但这是一般性的想法。

还要注意,如果您想在Web服务器之间共享数据,则可以使用分布式缓存

你也可以使用静态方法或静态注册的类实例,但请注意如果在IIS上托管,那么静态方法每次应用程序池重启时都会失效。因此,为了使其正常工作,需要使用类似刷新模式重新填充数据。

主要区别在于,使用缓存时有超时设置,可用于优化数据在缓存中存储的时间(硬时间限制或滑动过期)。


我希望避免不得不将其注入到每个控制器中。也许可以注入到视图组件中? - Laurie Dickinson
1
那也可以。控制器是依赖注入最常见的地方(这就是我选择该示例的原因),但它不是唯一的地方。正如我在答案中提到的,确实改进此解决方案 - 创建自己的包装器,围绕缓存注入到每个地方并公开缓存元素作为强类型属性是完全可以的。 - NightOwl888
1
我已经在视图组件中让它工作了,同时当组织信息被编辑时,我还从缓存中移除了该项。感谢您的帮助。 - Laurie Dickinson
我喜欢这个解决方案并想使用它。我的情况不同之处在于,我想在应用程序级别缓存项目列表,并且我希望能够从任何用户会话中添加或附加到列表,并使所有用户在下一次请求时都可以使用新信息。我每次都应该获取/设置整个列表吗?在附加/预置之前,我应该锁定列表吗? - shindigo

10

你可以创建一个名为ApplicationWideSettings的单例类。给该类公共的属性(Properties)。初始化所有需要的值一次,然后通过访问类的唯一实例来使用它们:

ApplicationWideSettings.Instance.PropertyName;

访问ApplicationWideSettings类时,请确保引用其命名空间。

与全局/静态设置相比,我更喜欢这种方法,因为你只需要一个类来保存所有全局可用的数据。

如果您不确定Singleton是什么,我建议您阅读Jon Skeet的这篇文章:

C#深入剖析:在C#中实现Singleton模式


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接