views:

1251

answers:

6

I'm needing to cache some data using System.Web.Caching.Cache. Not sure if it matters, but the data does not come from a database, but a plethora of custom objects.

The ASP.NET MVC is fairly new to me and I'm wondering where it makes sense for this caching to occur?

Model or Controller?

At some level this makes sense to cache at the Model level but I don't necessarily know the implications of doing this (if any). If caching were to be done at the Controller level, will that affect all requests, or just for the current HttpContext?

So... where should application data caching be done, and what's a good way of actually doing it?

Update

Thanks for the great answers! I'm still trying to gather where it makes most sense to cache given different scenarios. If one is caching the entire page, then keeping it in the view makes sense but where to draw the line when it's not the entire page?

+3  A: 

I don't know the anwser to your question, but Jeff Atwood talks about how the SO team did caching using the MVC framework for stackoverflow.com on a recent hanselminutes show that might help you out:

http://www.hanselminutes.com/default.aspx?showID=152

Ely
Thanks! Funny enough I actually listened to this a few days ago. Unfortunately, I couldn't really make heads or tails of the details of their solution. Who knows, it may have just went a little over my head. :)
Scott Saad
I listened to this as well, and I didn't think it was obvious *where* they'd implemented caching with respect to answering this question - though the discussion and subsequent blog post by Scott Hanselman about zipping cache content is very interesting!
Andrew
+1  A: 

I think the caching should somehow be related to the model. I think the controller shouldn't care more about the data. The controller responsibility is to map the data - regardless where it come from - to the views.

Try also to think why you need to cache? do you want to save processing, data transmission or what? This will help you to know where exactly you need to have your caching layer.

mnour
+6  A: 

I think it ultimately depends on what you are caching. If you want to cache the result of rendered pages, that is tightly coupled to the Http nature of the request, and wuold suggest a ActionFilter level caching mechanism.

If, on the other hand, you want to cache the data that drives the pages themselves, then you should consider model level caching. In this case, the controller doesn't care when the data was generated, it just performs the logic operations on the data and prepares it for viewing. Another argument for model level caching is if you have other dependencies on the model data that are not attached to your Http context.

For example, I have a web-app were most of my Model is abstracted into a completely different project. This is because there will be a second web-app that uses this same backing, AND there's a chance we might have a non-web based app using the same data as well. Much of my data comes from web-services, which can be performance killers, so I have model level caching that the controllers and views know absolutely nothing about.

Matt
+1  A: 

It all depends on how expensive the operation is. If you have complicated queries then it might make sense to cache the data in the controller level so that the query is not executed again (until the cache expires).

Keep in mind that caching is a very complicated topic. There are many different places that you can store your cache:

  • Akamai / CDN caching
  • Browser caching
  • In-Memory application caching
  • .NET's Cache object
  • Page directive
  • Distributed cache (memcached)
David P
+1  A: 

I would choose caching at the model level. (In general, the advice seems to be to minimize business logic at the controller level and move as much as possible into model classes.)

How about doing it like this:

I have some entries in the model represented by the class Entry and a source of entries (from a database, or 'a plethora of custom objects'). In the model I make an interface for retrieving entries:

public interface IEntryHandler
{
    IEnumerable<Entry> GetEntries();
}

In the model I have an actual implementation of IEntryHandler where the entries are read from cache and written to cache.

public class EntryHandler : IEntryHandler
{
    public IEnumerable<Entry> GetEntries()
    {
     // Check if the objects are in the cache:
     List<Entry> entries = [Get entries from cache]
     if (entries == null)
     {
      // There were no entries in the cache, so we read them from the source:
      entries = [Get entries from database or 'plethora of custom objects']
      [Save the retrieved entries to cache for later use]
     }
     return entries;
    }
}

The controller would then call the IEntryHandler:

public class HomeController : Controller
{
    private IEntryHandler _entryHandler;

    // The default constructor, using cache and database/custom objects
    public HomeController()
     : this(new EntryHandler())
    {
    }

    // This constructor allows us to unit test the controller 
    // by writing a test class that implements IEntryHandler
    // but does not affect cache or entries in the database/custom objects
    public HomeController(IEntryHandler entryHandler)
    {
     _entryHandler = entryHandler;
    }

    // This controller action returns a list of entries to the view:
    public ActionResult Index()
    {
     return View(_entryHandler.GetEntries());
    }
}

This way it is possible to unit test the controller without touching real cache/database/custom objects.

Ole Lynge
+2  A: 

Quick Answer

I would start with CONTROLLER caching, use the OutputCache attribute, and later add Model caching if required. It's quicker to implement and has instant results.

Detail Answer (cause i like the sound of my voice)

Here's an example.

[OutputCache(Duration=60, VaryByParam="None")]
public ActionResult CacheDemo() {
  return View();
}

This means that if a user hits the site (for the cache requirements defined in the attribute), there's less work to get done. If there's only Model caching, then even though the logic (and most likely the DB hit) are cached, the web server still has to render the page. Why do that when the render result will always be the same?

So start with OutputCaching, then move onto Model caching as you performance test your site.

Output caching is also a lot simpler to start out with. You don't have to worry about web farm distributed caching probs (if you are part of a farm) and the caching provider for the model.

Advanced Caching Techniques

You can also apply donut caching -> cache only part of the UI page :) Check it out!

Pure.Krome