0

I am building a online shop website. I want to display ProductCategory as a Sidebar (short list categories, Eg Clothes, Electronics, Furniture, Books, etc).

At the end, I want to send around productcategory _cache variable to all controllers.Does this methodology seem correct? Additionally, how do I remove unnecessary memorycache parameter in Home Controller? Make a method in Scheduled stuff to retrieve it?

DI Solution:

public class HomeController : Controller
{    
   private readonly IMemoryCache _cache;
   public IScheduledStuff _scheduledstuff;
   public HomeController(IMemoryCache cache, IScheduledStuff scheduledstuff)
   {
        _cache = cache;
        _scheduledstuff = scheduledstuff;
        _scheduledstuff.ScheduleItemsExecute();
    }
    public IActionResult Index()
    {
        ViewBag.ProductCategoryList = _cache.Get<IEnumerable<ProductCategory>>("Teststore");
        return View();
    }
}

public class ProductCategoryRepository : IProductCategoryRepository<ProductCategory>
{
    public IEnumerable<ProductCategory> GetAllProductCategory()
    {
        return _context.ProductCategory.ToList();
    }
}

public ProductCategory()
{
    public int ProductCategoryId { get; set; }
    public string ProductCategoryName { get; set; }
    public string ProductCategoryDescription { get; set; }
}

public class ScheduledStuff : IScheduledStuff
{
    private readonly DatabaseContext _context;
    IMemoryCache MemCache;
    public IProductCategoryRepository<ProductCategory> productcategoryrepository;

    public ScheduledStuff(DatabaseContext context, IMemoryCache memCache)
    {
        _context = context;
        MemCache = memCache;
        productcategoryrepository = new ProductCategoryRepository(_context);
    }

    public void ScheduleItemsExecute()
    {
        var testdata = productcategoryrepository.GetAllProductCategory();
        MemCache.Set("Teststore", testdata);
    }
}


public class Startup
{
    public IProductCategoryRepository<ProductCategory> productcategoryrepository;
    public IMemoryCache memorycache;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMemoryCache();
        services.AddSingleton<ScheduledStuff>();

Asp.Net Core: Use memory cache outside controller

Solution Static: Keep receiving Null exception error, can someone help fix this?

public static class MemoryCacheStatic
{
    public static IMemoryCache MemCacheStatic;
    public static IProductCategoryRepository<ProductCategory> productcategoryrepositorystatic;

    // Error on this line: <--- NullReferenceException: Object reference not set to an instance of an object.
    public static IEnumerable<ProductCategory> ProductCategoryStatic = productcategoryrepositorystatic.GetAllProductCategory();   


     public static void SetValues()
     {
        ProductCategoryStatic = productcategoryrepositorystatic.GetAllProductCategory();
        MemCacheStatic.Set("Teststore", ProductCategoryStatic) ;
     }
  • `Another Solution: However, this does not seem right.` could you explain ? – BRAHIM Kamel Sep 29 '18 at 20:51
  • well, it seem I have a lot of lists to load (5+), should I just place them all in ConfigureServices, or make them global? –  Sep 29 '18 at 21:06
  • 1
    AspNet Core is build around DI, you already use constructor injection. That is all you need. And your code sample is totally invalid, non compiling. Makes it hard to understand your problem. Just use [`services.AddMemoryCache();`](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-2.1) – H H Sep 29 '18 at 21:21
  • thats another thing, trying to get the configure services to compile, still working on it, just want to make sure I am on correct path, so you are recommending configureservices path I assume –  Sep 29 '18 at 21:24
  • You can't declare public fields/properties inside a method. And yes, go with the flow. Less work, less errors. – H H Sep 29 '18 at 21:25
  • @HenkHolterman I believe @MartinParker wanted to avoid redeclaring an `IMemoryCache` member in each controller, which he would still have to do with DI (in addition to having the extra parameter in his controller constructors). – RWRkeSBZ Sep 29 '18 at 22:12
  • Maybe, the question isn't clear. But that would be a bad and unwise requirement. – H H Sep 29 '18 at 22:26
  • that is correct, I wanted to avoid declaring memory cache in each controller, I have around 14 controllers, etc- –  Sep 30 '18 at 02:30
  • Then do declare it 14 times, or a 100 times if necessary. This is not something to exchange for a strong coupling. And avoid `static` wherever you can, especially in server apps. – H H Sep 30 '18 at 08:29
  • how would I pass scheduledstuff , to another controller? Should i create a variable like out - void ConfigureServices(IServiceCollection services, out ScheduledStuff scheduledstuff) ? –  Sep 30 '18 at 09:23
  • You're doing too much. After `AddSingleton();` you can inject the single instance everywhere. No need for a cache. – H H Sep 30 '18 at 18:57
  • not sure if I get it, can someone just write it in answer, trying using the resource link and how I'd pass it to controller, trying to integrate productcategory respository and scheduledstuff –  Sep 30 '18 at 19:14
  • hi Henk, if you have any git hub repository with good coding examples, I would be happy to learn from it, thanks –  Oct 02 '18 at 06:00

3 Answers3

1

This should work, thanks for the help Henk-

public class HomeController : Controller
{    
   private readonly IMemoryCache _cache;
   public IScheduledStuff _scheduledstuff;
   public HomeController(IMemoryCache cache, IScheduledStuff scheduledstuff)
   {
        _cache = cache;
        _scheduledstuff = scheduledstuff;
        _scheduledstuff.ScheduleItemsExecute();
    }
    public IActionResult Index()
    {
        ViewBag.ProductCategoryList = _cache.Get<IEnumerable<ProductCategory>>("Teststore");
        return View();
    }
}

public class ProductCategoryRepository : IProductCategoryRepository<ProductCategory>
{
    public IEnumerable<ProductCategory> GetAllProductCategory()
    {
        return _context.ProductCategory.ToList();
    }
}

public ProductCategory()
{
    public int ProductCategoryId { get; set; }
    public string ProductCategoryName { get; set; }
    public string ProductCategoryDescription { get; set; }
}

public class ScheduledStuff : IScheduledStuff
{
    private readonly DatabaseContext _context;
    IMemoryCache MemCache;
    public IProductCategoryRepository<ProductCategory> productcategoryrepository;

    public ScheduledStuff(DatabaseContext context, IMemoryCache memCache)
    {
        _context = context;
        MemCache = memCache;
        productcategoryrepository = new ProductCategoryRepository(_context);
    }

    public void ScheduleItemsExecute()
    {
        var testdata = productcategoryrepository.GetAllProductCategory();
        MemCache.Set("Teststore", testdata);
    }
}


public class Startup
{
    public IProductCategoryRepository<ProductCategory> productcategoryrepository;
    public IMemoryCache memorycache;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMemoryCache();
        services.AddSingleton<ScheduledStuff>();
-1

Cache is one of those few things that are good candidates for the Singleton design pattern. Plus, it is thread-safe. Just make a global cache object that is accessible to all that need it.

RWRkeSBZ
  • 723
  • 4
  • 11
  • so to clarify, option one - global pattern, and don't place everthing in configureservices? –  Sep 29 '18 at 21:16
  • A static wrapper class that holds a reference to a static instance of MemoryCache. But, for testability, allow setting the instance of MemoryCache via a setter. Or, as @David says in his answer. – RWRkeSBZ Sep 29 '18 at 21:21
-1

I solved this issue with a static CacheHelper class. You can call this static class from any controller . You can get more ideas about how to implement it here: How to cache data in a MVC application

Desmond
  • 406
  • 5
  • 7
  • does not seem to work in net core 2, can you try it out? –  Sep 29 '18 at 21:23
  • I don't think the general pattern is subject to change with certain framework. Just make a "public static class CacheHelper" class and make a "GetFromCache" function that you can call from any controller. In your "GetFromCache" function you can request the object from cache, and if it isn't present you can call it from your database and fill the cache with it. You always return the object you need whether you got it from cache or from the database. – Desmond Sep 29 '18 at 21:28
  • ok, well I was receiving a compilation error in netcore2 when trying out- –  Sep 29 '18 at 21:29
  • almost done writing static Memorycache, receiving error above though –  Sep 30 '18 at 04:08
  • You shouldn't initiate ProductCategoryStatic as a default value in the static class. When it get's there probably things aren't ready to call that, that's the reason of the error. Do it inside a procedure that you call to get the value. Something like this: GetValue { If (inCache) { get it from cache and return the value } else { get it from database, save it in cache and return the value } } – Desmond Sep 30 '18 at 21:01