在ASP.NET Core的startup类中如何使用MemoryCache

时间:2022-06-22 03:31:14

问:


下面的代码,在ASP.NET Core的startup类中创建了一个MemoryCache并且存储了三个键值“entryA”,“entryB”,“entryC”,之后想在Controller中再把这三个键值从缓存中取出来,但是发现Controller中的构造函数依赖注入的IMemoryCache并不是startup类中的MemoryCache,因为Controller中的IMemoryCache没有任何键值对:

How do I access the MemoryCache instance in Startup that will be used by the rest of my web app? This is how I'm currently trying it:

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        //Startup stuff
    }

    public void ConfigureServices(IServiceCollection services)
    {
        //configure other services

        services.AddMemoryCache();

        var cache = new MemoryCache(new MemoryCacheOptions());
        var entryOptions = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove);

        //Some examples of me putting data in the cache
        cache.Set("entryA", "data1", entryOptions);
        cache.Set("entryB", data2, entryOptions);
        cache.Set("entryC", data3.Keys.ToList(), entryOptions);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        //pipeline configuration
    }
}

And the Controller where I use the MemoryCache

public class ExampleController : Controller
{   
    private readonly IMemoryCache _cache;

    public ExampleController(IMemoryCache cache)
    {
        _cache = cache;
    }

    [HttpGet]
    public IActionResult Index()
    {
        //At this point, I have a different MemoryCache instance.
        ViewData["CachedData"] = _cache.Get("entryA");//这里"entryA"从IMemoryCache中找不到,为null

        return View();
    }
}

 

答:


When you added the statement

services.AddMemoryCache();

you were in effect saying that you wanted a memory cache singleton that would get resolved wherever you injected IMemoryCache as you did in your controller. So instead of creating a new memory cache, you need to add values to the singleton object that was created. You can do this by changing your Configure method to something like:

public void Configure(IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory,
        IMemoryCache cache )
{
    var entryOptions = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove);

    //Some examples of me putting data in the cache
    cache.Set("entryA", "data1", entryOptions);
    cache.Set("entryB", data2, entryOptions);
    cache.Set("entryC", data3.Keys.ToList(), entryOptions);
    //pipeline configuration
}

Use Configure method, not ConfigureServices。

 

意思就是说在ASP.NET Core的startup类中Configure方法是在ConfigureServices方法之后执行的,而如果在ConfigureServices方法中调用了services.AddMemoryCache()来启用MemoryCache的依赖注入,那么就可以在Configure方法的参数中使用IMemoryCache了,ASP.NET Core会自动注入Configure方法的IMemoryCache参数。并且在后续的Controller中注入的也是同一个IMemoryCache参数的实例。

 

ConfigureServices方法中调用了services.AddMemoryCache()来启用MemoryCache的依赖注入后,也可以直接在中间件的构造函数中使用IMemoryCache了,ASP.NET Core会自动注入中间件构造函数中IMemoryCache类型参数(和Configure方法及Controller等地方注入的是同一个实例的MemoryCache,保证了数据的互通)。比如下面代码中我们定义了一个UserProfileMiddleware中间件,其构造函数就有一个IMemoryCache类型的参数cache,当调用UserProfileMiddleware中间件时,ASP.NET Core会自动注入IMemoryCache cache参数:

public class UserProfileMiddleware
{
    private readonly RequestDelegate next;
    private readonly IMemoryCache cache;

    public UserProfileMiddleware(
        RequestDelegate next,
        IMemoryCache cache)
    {
        this.next = next;
        this.cache = cache;
    }

    public async Task Invoke(
        Microsoft.AspNetCore.Http.HttpContext context)
    {
        if (UserProfile.cache == null)
        {
            UserProfile.cache = cache;
        }

        await next.Invoke(context);
    }
}

 

 

原文链接