问:
下面的代码,在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); } }