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 obj
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.
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 would 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.
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:
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
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.
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 OutputCach
ing, 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.
You can also apply donut caching -> cache only part of the UI page :) Check it out!
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.