我想将项目存储在应用程序缓存中,以便从主布局视图中延迟加载。
我还希望能够使缓存无效,所以如果它无效,下次请求items-collection时,它会重新加载到缓存位置。
这是我实施的内容:
在控制器中:
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;
}
我是视图(更好地在'a'视图中说,我希望能够从每个视图加载它):
@{
var sliderController = new LevEl.Controllers.Admin.SliderController().
var sliderModel = sliderController.GetSlides();
}
它抛出异常,因为当我在视图中初始化控制器时,HttpContext
属性返回null(导致NullReferenceException
)。
欢迎任何其他实现方法。
答案 0 :(得分:4)
首先,您可能需要考虑使用Cache而不是Application字典,特别是因为您的缓存数据将在某个时候到期。看看this question
另外,请考虑控制器方法是否仅由视图使用,因为MVC将公开控制器中的所有公共方法。如果您不希望使用网址自由访问此方法,请设置[NonAction]
attribute。
关于您的错误,修复它的一种快速方法是在控制器的CachedSlides属性的实现中通过System.Web.HttpContext.Current
访问Application对象。
您还可以在视图中创建SliderController的新实例时设置ControllerContext。这样,当访问CachedSlides属性时,控制器中的HttpContext将不返回null:
@{
var sliderController = new LevEl.Controllers.Admin.SliderController();
sliderController.ControllerContext = new ControllerContext(ViewContext.RequestContext, sliderController);
var sliderModel = sliderController.GetSlides();
}
如果你有一个能够处理所有这些视图的基本控制器类是有意义的,那么获得控制器会更清晰。您只需要将ViewContext.Controller
实例强制转换为基本控制器类:
var sliderController = ViewContext.Controller as BaseSlideController;
var sliderModel = sliderController.GetSlides();
但是,所有这些方法都需要您将这段代码添加到每个视图中。您可以考虑为所有需要访问Slide集合的视图设置基类:
public abstract class SlidesEnabledView<T> : WebViewPage<T>
{
private IEnumerable<Slide> _slides;
protected IEnumerable<Slide> Slides
{
get
{
if(_slides == null)
{
var sliderController = ViewContext.Controller as BaseSlideController;
_slides = sliderController.GetSlides();
}
return _slides;
}
}
}
然后您将@inherits标记添加到您的视图中,因此它们从我们刚创建的基类继承(当使用@inherits时,您也不能使用@model,所以在@inherits中您将绑定通用基本视图类型ti具体模型类型)。这将允许您使用基本SlidesEnabledView
视图类中定义的属性。假设SlidesEnabledView的命名空间是Level.ViewClasses.Admin,这看起来像:
@inherits Level.ViewClasses.Admin.SlidesEnabledView<SomeViewModelClass>
Number of Slides: @Slides.Count()
最后,如果您通过网站使用DI并且已经配置了DependencyResolver,那么您可以考虑将幻灯片移动到其自己的类和界面(如ISlidesProvider
和CachedSlideProvider
)。然后,您可以在抽象视图类中使用属性注入来获取将在Slides属性中使用的ISlidesProvider实例:
public interface ISlidesProvider
{
IEnumerable<Slide> GetSlides();
}
public class CachedSlideProvider : ISlidesProvider
{
//you will need a constructor that takes the "Context" object, which will be injected into this class
public IEnumerable<Slide> GetSlides()
{
if (CachedSlides == null)
CachedSlides = Context.Slides.OrderBy(p => p.SortOrder).ToArray();
return CachedSlides;
}
private IEnumerable<Slide> CachedSlides
{
get { return System.Web.HttpRuntime.Cache[SlidesCacheKey] as IEnumerable<Slide>; }
set { System.Web.HttpRuntime.Cache[SlidesCacheKey] = value; }
}
}
public abstract class SlidesEnabledView<T> : WebViewPage<T>
{
private IEnumerable<Slide> _slides;
protected IEnumerable<Slide> Slides
{
get
{
if(_slides == null)
{
_slides = this.SlidesProvider.GetSlides();
}
return _slides;
}
}
//This property will be set by your DI container
//You have configured ISlidesProvider to be resolved as CachedSlidesProvider in the DI container
//You have also implemented and registered an MVC DependencyResolver that uses your DI container
//For example, using Microsoft Unity you could set this attribute
[Dependency]
public ISlidesProvider SlidesProvider { get; set; }
}
当您使用无参数构造函数创建控制器实例时,可能您没有在您的站点上使用DI。所以这个DI选项对于解决这个特殊问题可能有点过分。
答案 1 :(得分:1)
您可以在GetSlides
:
BaseController
方法
public class BaseController : Controller
{
protected IEnumerable<Slide> CachedSlides
{
get { return HttpContext.Application[SlidesCacheKey] as IEnumerable<Slide>; }
set { HttpContext.Application[SlidesCacheKey] = value; }
}
private void ClearSlides()
{
CachedSlides = null;
}
public IEnumerable<Slide> GetSlides()
{
if (CachedSlides == null)
CachedSlides = Context.Slides.OrderBy(p => p.SortOrder).ToArray();
return CachedSlides;
}
}
因此,所有控制器都必须从BaseController
继承。
在视图中,您可以这样做:
@{
var baseController = (BaseController)ViewContext.Controller;
var slides = baseController.GetSlides();
}