3

我想将项目存储在应用程序缓存中,以便从主布局视图中延迟加载。

我还希望能够使缓存无效,所以如果它无效,下次请求项目集合时,它会重新加载到该缓存位置。

这是我已经实现的:

在控制器中:

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 (这导致 a NullReferenceException)。

任何其他实现这一点的方法也将受到欢迎。

4

2 回答 2

4

首先,您可能需要考虑使用 Cache 而不是 Application 字典,特别是因为您的缓存数据将在某个时候过期。看看这个问题

另外,请考虑控制器方法是否仅由视图使用,因为 MVC 将公开控制器中的所有公共方法。如果您不希望使用 URL 自由访问此方法,请设置[NonAction] 属性

关于您的错误,修复它的一种快速方法是通过System.Web.HttpContext.Current控制器的 CachedSlides 属性的实现来访问 Application 对象。

您还可以在视图中创建 SliderController 的新实例时设置 ControllerContext。这样,控制器中的 HttpContext 在访问 CachedSlides 属性时不会返回 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 中您将绑定通用基类视图类型是具体的模型类型)。这将允许您使用在基本SlidesEnabledView视图类中定义的属性。假设 SlidesEnabledView 的命名空间是 Level.ViewClasses.Admin,这看起来像:

@inherits Level.ViewClasses.Admin.SlidesEnabledView<SomeViewModelClass> 

Number of Slides: @Slides.Count() 

最后,如果您通过您的站点使用 DI 并且您已经配置了一个 DependencyResolver,那么您可以考虑将获取幻灯片的逻辑移动到它自己的类和接口中,例如ISlidesProviderand 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 选项可能有点矫枉过正。

于 2012-12-16T13:16:36.360 回答
1

您可以在 a 中定义您的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();
}
于 2012-12-16T11:58:55.330 回答