4

我在 MVC 中有这个动作

[OutputCache(Duration = 1200, VaryByParam = "*")]
public ActionResult FilterArea( string listType, List<int> designersID, int currPage = 1 )
{
   // Code removed
}

未能显示正确的 HTML 与 url 之类的

这是 .NET 中 OutputCache 的已知错误导致无法识别带有列表参数的 VaryByParam 还是我遗漏了什么?

4

1 回答 1

1

我在 MVC3 中也有同样的问题,我相信在 MVC5 中它仍然是同样的情况。

这是我的设置。

要求

POST,Content-Type:application/json,传入一个字符串数组作为参数

{ "options": ["option1", "option2"] }

控制器方法

[OutputCache(Duration = 3600, Location = OutputCacheLocation.Any, VaryByParam = "options")]
public ActionResult GetOptionValues(List<string> options)

我尝试了使用 OutputCache 的所有可能选项,但它并没有为我缓存。绑定对于实际工作的方法来说工作得很好。我最大的怀疑是 OutputCache 没有创建唯一的缓存键,所以我什至将其代码拉出来System.Web.MVC.OutputCache进行验证。我已经验证,即使List<string>传入 a ,它也能正确构建唯一键。那里有其他东西是错误的,但不值得花更多的精力。

OutputCacheAttribute.GetUniqueIdFromActionParameters(filterContext,
                OutputCacheAttribute.SplitVaryByParam(this.VaryByParam);

解决方法

在另一篇 SO 帖子之后,我最终创建了自己的 OutputCache 属性。更容易使用,我可以享受一天的剩余时间。

控制器方法

[MyOutputCache(Duration=3600)]
public ActionResult GetOptionValues(Options options)

自定义请求类

我继承自,List<string>所以我可以调用.ToString()MyOutputcache 类中的覆盖方法来给我一个唯一的缓存键字符串。仅这种方法就为其他人解决了类似的问题,但对我却没有。

[DataContract(Name = "Options", Namespace = "")]
public class Options: List<string>
{
    public override string ToString()
    {
        var optionsString= new StringBuilder();
        foreach (var option in this)
        {
            optionsString.Append(option);
        }
        return optionsString.ToString();
    }
}

自定义 OutputCache 类

public class MyOutputCache : ActionFilterAttribute
{
    private string _cachedKey;

    public int Duration { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.Url != null)
        {
            var path = filterContext.HttpContext.Request.Url.PathAndQuery;
            var attributeNames = filterContext.ActionParameters["Options"] as AttributeNames;
            if (attributeNames != null) _cachedKey = "MYOUTPUTCACHE:" + path + attributeNames;
        }
        if (filterContext.HttpContext.Cache[_cachedKey] != null)
        {
            filterContext.Result = (ActionResult) filterContext.HttpContext.Cache[_cachedKey];
        }
        else
        {
            base.OnActionExecuting(filterContext);
        }
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        filterContext.HttpContext.Cache.Add(_cachedKey, filterContext.Result, null,
            DateTime.Now.AddSeconds(Duration), System.Web.Caching.Cache.NoSlidingExpiration,
            System.Web.Caching.CacheItemPriority.Default, null);
        base.OnActionExecuted(filterContext);
    }
}
于 2014-08-09T19:07:16.137 回答