9

I am trying to port some libraries from the old MVC5 System.Web based stack to .Net Core. One issue I am having is the changes in the caching. For example, in MVC5 I was able to read and write i18n related data:

[Code Snippet 1]

public static Dictionary<string, IEnumerable<CoreDictionaryResource>> DictionaryResourcesCache {
    get { return (Dictionary<string, IEnumerable<CoreDictionaryResource>>)HttpContext.Current.Cache(string.Concat(_Dictionary, DictionaryID, CultureID)); }
    set { HttpContext.Current.Cache(string.Concat(_Dictionary, DictionaryID, CultureID)) = value; }
}

However, I am reliably informed that System.Web and its HttpContext does not contain a Cache field. I can see a Current field and then a whole host of fields within this such as Application and Session but alas no Cache.

I've done the necessary in Startup.cs and the app is configured to use both in memory caching and sessions. I know that the sessions work as I have other POCOs cached using

[Code Snippet 2]

 return System.Web.HttpContext.Current.Session.GetObject<User>("AuthenticatedUser");

where GetObject in an extension I created.

Am I barking up the wrong tree trying to use HttpContext to read out from the Cache or perhaps I need to use IDistributedCache as see here, here and on SO.

But really I just to port the method within [Code Snippet 1]...

Any pointer you can give on the new .Net Core with regards to caching would be really helpful.

Just FYI I do not want any logic in Controllers, nor in Views. The application I am building usings separate DLLs for data access and logic so please don't post any examples with DI into the Controllers. This issue is more at an infrastrcture level before it hits the MVC stack.

Thanks guys and gals.

Community
  • 1
  • 1
o-o-awake-o-o
  • 397
  • 1
  • 3
  • 18
  • Also, our i18n strings are not stored with XML but within a bespoke DB instance... However, this shouldn't be an issue as the CRUD methods within the data access layer are operating correctly. I just need to work out how to cache these server side and read them out. – o-o-awake-o-o Dec 13 '16 at 10:23
  • But now, you can register memory (or distributed cache like Redis) in startup with `services.AddMemoryCache();`, then resolve `IDistributedCache` or `IMemoryCache` and resolve it in your middleware. You just can't use static fields, as its against the IoC/DI nature of ASP.NET Core and an anti pattern. Or you create a class for it which wraps the logic around it. Or just use the new localization feature that's wrapping around an database or memory cache, – Tseng Dec 13 '16 at 11:40
  • see see https://github.com/damienbod/AspNet5Localization/blob/master/AspNet5Localization/src/Localization.SqlLocalizer/DbStringLocalizer/SqlStringLocalizer.cs for sql server example – Tseng Dec 13 '16 at 11:40
  • Thanks Tseng - duly noted. Unforunately, IoC/DI is not a sacred cow (indeed SO themselves do not use DI because it can become convoluted and slow). However, the `IDistributedCache` seems a good option. Was thinking of AWS Elasticache instead of Redis but hey! Pigs is pigs. Did you have an example or link to resources on `"new localization feature that's wrapping around an database or memory cache"` – o-o-awake-o-o Dec 13 '16 at 14:02
  • The link in my second command links to a file/repository which shows it. Usage of the localizer is described in the docs here http://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization – Tseng Dec 13 '16 at 15:51
  • The accepted answer shows another way to do it, but I just posted a way to do it exactly how you asked for. In other words, it's possible to use an equivalent of `HttpContext.Current.Cache("key")` on asp.net core, and my answer shows how to do it. – Vitox Sep 29 '20 at 19:33

3 Answers3

11

The in memory cache functionality is still there, it has just been moved around a bit. If you add

"Microsoft.Extensions.Caching.Memory": "1.1.0"

to you project.json file and the add

        services.AddMemoryCache();

to you Startup.ConfigureServices method, you'll have set up a singleton memory cache instance that works pretty much like the old one did. You get to it via dependency injection so a controller with a constructor can get a instance.

public class HomeController: Controller 
{
    private IMemoryCache _cache;
    public HomeController(IMemoryCache cache) 
    {
        _cache = cache;
    }

}

You can then use _cache in the class above to get to the globally available singleton class. There are other sorts of caches that you might want look at as well, including a Redis cache for out of process storage.

GlennSills
  • 3,977
  • 26
  • 28
  • I was getting this error: "Could not create an instance of type 'Microsoft.Extensions.Caching.Memory.IMemoryCache'. Model bound complex types must not be abstract or value types and must have a parameterless constructor." - To fix it you just need to change it like this: public HomeController([FromServices] IMemoryCache cache) – Valerio Gentile Oct 15 '18 at 11:25
5

You should use the In Memory Cache only as HttpContext cache object was actually appdomain cache object although it is exposed using the HttpContext

From the msdn https://msdn.microsoft.com/en-us/library/system.web.httpcontext.cache(v=vs.110).aspx

There is one instance of the Cache class per application domain. As a result, the Cache object that is returned by the Cache property is the Cache object for all requests in the application domain.

We should use the

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Memory;
using System;
using Microsoft.Extensions.FileProviders;

namespace CachingQuestion
{
public class Startup
{
    static string CACHE_KEY = "CacheKey";

    public void ConfigureServices(IServiceCollection services)
    {
        //enabling the in memory cache 
        services.AddMemoryCache();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var fileProvider = new PhysicalFileProvider(env.ContentRootPath);

        app.Run(async context =>
        {
            //getting the cache object here
            var cache = context.RequestServices.GetService<IMemoryCache>();
            var greeting = cache.Get(CACHE_KEY) as string;


        });
    }
}

 public class Program
 {
    public static void Main(string[] args)
    {
          var host = new WebHostBuilder()
            .UseKestrel()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}
}
Rohith
  • 5,527
  • 3
  • 27
  • 31
1

My answer is focused on how to port caching implementation from old ASP.Net MVC to ASP.Net CORE the easiest and fastest way possible, and also focusing on not rely on dependency injection.


There is a perfect equivalent of ASP.Net MVC's HttpContext.Current.Cache. Its implementation was intended exactly to permit easy porting between frameworks. This is:

System.Runtime.Caching/MemoryCache
This is pretty much the same as the old day's ASP.Net MVC's HttpRuntime.Cache. You can use it on ASP.Net CORE without any dependency injection. This is how to use it:

// First install 'System.Runtime.Caching' (NuGet package)

// Add a using
using System.Runtime.Caching;

// To get a value
var myString = MemoryCache.Default["itemCacheKey"];

// To store a value
MemoryCache.Default["itemCacheKey"] = myString;
Vitox
  • 3,852
  • 29
  • 30