ASP.NET MVC 3 自定义路由基类和输出缓存

10
我有一个关于自定义的RouteBase实现和[OutputCache]的问题。 我们有一个CMS,其中URL映射到特定的内容页面。每种类型的内容页面由不同的控制器(和不同的视图)处理。这些URL完全自由,我们需要不同的控制器,因此“catch-all”路由不能使用。因此,我们构建了一个自定义的RouteBase实现,该实现调用数据库查找所有的URL。数据库知道使用哪个控制器和操作(基于内容页面类型)。
这很有效。
但是,与[OutputCache]属性结合使用时,输出缓存不起作用(页面仍然可以访问)。我们确保[OutputCache]在我们的“普通”路由上起作用。
调试输出缓存非常困难,虽然属性存在,但却无法正常工作...如何解决这个问题的想法将非常受欢迎,正确答案也是如此!
控制器代码如下:
public class TextPageController : BaseController
{
  private readonly ITextPageController textPageController;

  public TextPageController(ITextPageController textPageController)
  {
    this.textPageController = textPageController;
  }

  [OutputCache(Duration = 300)]
  public ActionResult TextPage(string pageid)
  {
    var model = textPageController.GetPage(pageid);
    return View(model);
  }
}

自定义路由的样子是这样的:

public class CmsPageRoute : RouteBase
{
  private IRouteService _routeService;
  private Dictionary<string, RouteData> _urlsToRouteData;

  public CmsPageRoute(IRouteService routeService)
  {
    this._routeService = routeService;
    this.SetCmsRoutes();
  }

  public void SetCmsRoutes()
  {
    var urlsToRouteData = new Dictionary<string, RouteData>();
    foreach (var route in this._routeService.GetRoutes()) // gets RouteData for CMS pages from database
    {
      urlsToRouteData.Add(route.Url, PrepareRouteData(route));
    }
    Interlocked.Exchange(ref _urlsToRouteData, urlsToRouteData);
  }

  public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
  {
    RouteData routeData;
    if (_urlsToRouteData.TryGetValue(httpContext.Request.Path, out routeData))
      return routeData;
    else
      return null;
  }

  public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
  {
    return null;
  }

  private RouteData PrepareRouteData(ContentRouteData contentRoute)
  {
    var routeData = new RouteData(this, new MvcRouteHandler());

    routeData.Values.Add("controller", contentRoute.Controller);
    routeData.Values.Add("action", contentRoute.Action);
    routeData.Values.Add("area", contentRoute.Area);
    routeData.Values.Add("pageid", contentRoute.Constraints["pageid"]); // variable for identifying page id in controller method

    routeData.DataTokens.Add("Namespaces", new[] { contentRoute.Namespace });
    routeData.DataTokens.Add("area", contentRoute.Area);

    return routeData;
  }

  // routes get periodically updated
  public void UpdateRoutes()
  {
    SetCmsRoutes();
  }
}

感谢您一直阅读到最后!


顺便提一下,我忘了提到我查看了性能计数器“ASP.NET应用程序/输出缓存条目”。当我成功将页面添加到缓存中时,它会升高,但当使用我的自定义RouteBase实现调用上述控制器时,则不会升高。 - Jaap
在周末,我将其解析为最小的示例,它可以正常工作。但是在我们的大型项目中却不能正常工作。 因此,我的努力应该集中于理解为什么它不能正常工作。调试输出缓存并不容易:( - Jaap
你想在哪里进行缓存?你希望IIS缓存你的页面还是希望客户端(浏览器)进行缓存?在IIS中进行缓存可能会比较困难,因为IIS可能只能处理简单形式的URL,但通过设置Response.Expires来在客户端计算机上进行缓存则相对容易。 - Akash Kava
我会尽快查看并为您提供解决方案。 - Pushpendra
你能更具体地说明一下“OutputCache不起作用”的意思吗? - smartcaveman
问题不在于自定义路由,而是当我们使用自定义路由时,某种方式(我们不知道是什么原因)设置的Cookie导致了问题。该Cookie始终被设置,并且对于非自定义路由页面,输出缓存正常工作,但对于由我们的自定义路由路由的页面则无法正常工作... - Jaap
3个回答

1
最终我们追踪到它是由一个调用引起的。
 ... data-role="@this.FirstVisit" ...

在我们的_Layout.cshtml

这个调用了我们自定义视图页面上的一个属性,该属性又调用了一个服务,该服务总是设置一个cookie。(天哪,在服务中设置cookie!我们知道这很危险!)

如果不是周五并且在冲刺结束时,我们可能会注意到缓存破坏Cache-Control: no-cache="Set-Cookie": Http头。

我仍然不明白为什么这只会破坏我们自定义RouteBase实现的缓存,而不是所有页面。所有页面都使用相同的_Layout.cshtml


0
你可以尝试以下代码,如果有帮助的话。
[OutputCache(Duration = 300, VaryByParam="*")] 
public ActionResult TextPage(string pageid) 
{ 
  var model = textPageController.GetPage(pageid); 
  return View(model);
}

VaryByParam="*" 是MVC 3中的默认设置。 - Jaap

0

谢谢,我找到了这些问题。 - Jaap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接