I want to store items in the application cache so it's lazy loaded from the main layout view.
I also want to be able to invalidate the cache, so if it's invalid, next time when the items-collection is requested, it's reloaded to that cache location.
Here's what I've implemented:
In the controller:
protected IEnumerable<Slide> CachedSlides
{
get { return HttpContext.Application[SlidesCacheKey] as IEnumerable<Slide>; }
set { HttpContext.Application[SlidesCacheKey] = value; }
}
private void ClearSlides()
{
CachedSlides = null;
}
[AllowAnonymous]
public IEnumerable<Slider> GetSlides()
{
if (CachedSlides == null)
CachedSlides = Context.Slides.OrderBy(p => p.SortOrder).ToArray();
return CachedSlides;
}
I the view (better said in 'a' view, I want to be able to load it from every view):
@{
var sliderController = new LevEl.Controllers.Admin.SliderController().
var sliderModel = sliderController.GetSlides();
}
It throws an exception because when I initialize the controller in the view, the HttpContext
property returns null (which leads to a NullReferenceException
).
Any other ways to implement this will also be welcome.
You could define your
GetSlides
method in aBaseController
:So all of your controllers have to inherit from
BaseController
.In the view you could do this:
First of all, you may want to consider using the Cache instead of the Application dictionary, specially since your cached data will expire at some point. Take a look at this question
Also, consider if the controller method will just be used by the views because MVC will expose all public methods in the controller. If you don´t want this method to be freely accessed using an URL then set the
[NonAction]
attribute.Regarding your error, a quick way to fix it will be accessing the Application object through
System.Web.HttpContext.Current
in the implementation of the CachedSlides property of the controller.You could also set the ControllerContext when creating a new instance of the SliderController in the view. That way, the HttpContext in the controller will not return null when accessing the CachedSlides property:
If it makes sense for you to have a base controller class that will handle all of these views, then getting the controller will be cleaner. You would just need to cast the
ViewContext.Controller
instance as that base controller class:However all of those approaches will require you to add that piece of code to every view. You may consider having a base class for all of your views that will require accessing the Slide collection:
You will then add the @inherits tag to your views, so they inherit from the base class we have just created (When the @inherits is used, you cannot also use the @model, so in the @inherits you will bound the generic base view type ti a concrete model type). This will allow you to use the property defined in the base
SlidesEnabledView
view class. Assuming the namespace for SlidesEnabledView is Level.ViewClasses.Admin, this would look like:Finally, if you are using DI through your site and you have configured a DependencyResolver, then you could consider moving the logic for getting the slides into its own class and interface like
ISlidesProvider
andCachedSlideProvider
. You could then use property injection in the abstract view class for getting an instance of ISlidesProvider that will be used in the Slides property:As you were creating an instance of the controller using a parameterless constructor, probably you are not using DI on your site. So this DI option may be a bit of overkill just for resolving this particular problem.