2014-08-27 53 views
4

我有一个webusercontrol使用公共int属性SelectedCatID。我用其他的页面和其他控件这种控制如下:使用webusercontrol获取输出缓存以在ASP.net中工作

<NewStore:LeftMenuLinks runat="server" SelectedCatID="<%#CatIDToSelect%>" /> 

我如何输出缓存基于SelectedCatID这个控制?我试过的一切都失败了。

我得到的最接近的是将它缓存到缓存中,但它在SelectedCatID上没有变化,所以选择相同的菜单项直到缓存过期。没有缓存,控制按预期工作。

+0

'VaryByControl'属性应该与用户控件的ID匹配缓存,而不仅仅是控件的任意属性。如果你检查后面的代码中存在控件,然后设置你的'NewStore:LeftMenuLinks'用户控件使用的变量,它是否工作? – Justin 2014-08-29 16:20:41

+0

您在数据绑定控件中是否具有SelectedCatID =“<%#SelectedCatID%>”版本,还是只绑定到页面类的属性? SelectedCatID和SelectedMenu之间的关系是什么?或者这只是一个错字? – 2014-09-02 12:07:11

+0

@menno错字,现在修复! – 2014-09-02 12:54:12

回答

0
<%@ OutputCache Duration="60" VaryByParam="SelectedCatID" %> 

现在存储您选择<%#CatIDToSelect%>作为一个参数e?SelectedCatID = 12 现在,您就取决于你想要根据请求需要缓存的内容将输出缓存的页面或用户控件。参数[“SelectedCatID”]等于。

你也可以做这样的事情(虽然不是最简单的方法)

这那张/用户控件你想缓存页面:

<%@ OutputCache duration="120" varybyparam="None" varybycustom="SelectedCatID" %> 

这进入Gloabal.asax文件:

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    if(custom == "SelectedCatID") 
    { 
     return CatIDToSelect; 
    } 
    return String.Empty; 
} 
+0

看看这个pastebin:http://pastebin.com/NLmZkfP9 它引发错误'CS0115:'Controls_Blog_LatestEntries.GetVaryByCustomString(System.Web.HttpContext,字符串)':找不到合适的方法来覆盖'。 缓存定义为'%@ OutputCache duration =“120”varybyparam =“None”varybycustom =“SelectedBlogID”%> 我明白从使用谷歌这是为了去global.asax,但这不是帮助我。我需要一种方法来缓存基于传递给iut的属性的控件 – 2014-09-02 15:30:57

+0

好吧,所以我测试了它似乎你不需要([OutputCache(CacheProfile =“CacheProfile”)]。并且一旦你刷新页面就工作了。它显示第二次刷新后的确切时间(包括秒)不再改变一个时间是永久性的,直到持续时间到期为止。只要按照我对测试代码进行的更改 – Hillboy 2014-09-02 16:59:23

+0

进行查看(4个文件):http:// pastebin .com/6v10bSgg http://pastebin.com/QFNXE7Z1 http://pastebin.com/Jbfuwywf http://pastebin.com/AXC2vT95 – Hillboy 2014-09-02 17:10:06

2

我想出了为什么最初使用的VaryByControls方法不起作用。可悲的是,你将它编辑出了你的问题,所以我的研究只能进入博客文章。更新:有问题的博文:http://tabeokatech.blogspot.be/2014/09/outputcache-on-user-controls.html。但它的长短之处在于,VaryByControls对于VaryByParams来说有点简单,并且对属性不做任何事情:它只查看POST值。事实上,它曾经为具有静态值的属性工作似乎是一个错误 - VaryByControls中的任何字符串都会使该部分工作。这个问题被接受的答案是错误的:Vary by control properties using PartialCaching in ASP.NET

没有内置方法可以根据控件属性值进行更改。

无论如何,这是没有意义的,因为用户控件需要创建具有属性值,并且您希望避免创建它们,而不是缓存它们的呈现标记 - 缓存的用户控件字段在代码隐藏中为空(如果已缓存)标记是为他们服务的。 这可以通过将PartialCachingControl注入页面而不是实际的用户控件来实现。此PartialCachingControl检查缓存,并且只在没有缓存版本存在的情况下创建控件。

至于使其工作,我看到两个选项:

  1. 如果你只有每页1个用户控件,您可以使用VaryByCustom是办法。为方便起见,你可以写一个返回你的属性值,该页面的界面,并实现它的每一页承载用户控件,例如:

    interface INumberProvider 
    { 
        int GetNumber(); 
    } 
    
    // and the page: 
    public partial class _Default : Page, INumberProvider 
    { 
        public int GetNumber() 
        { 
         return this.SomeNumberPropertyOrWhatever; 
        } 
    ... 
    

    在全局上。ASAX你投目前的处理程序INumberProvider并获得数:

    public override string GetVaryByCustomString(HttpContext context, string custom) 
        { 
         if (custom == "INumberProvider") 
         { 
          var page = context.CurrentHandler as INumberProvider; 
    
          if (page != null) 
          { 
           return page.GetNumber().ToString(); 
          } 
         } 
         return base.GetVaryByCustomString(context, custom); 
        } 
    

    而在你的控制,你明显增加:

    的OutputCache时间= “180” VaryByCustom是= “INumberProvider” 的VaryByParam = “无” 共享= “true”

    这就是说,如果每个页面只有一个用户控件,并且应该非常简单。如果每页需要多个用户控件,那么您的运气不好:

  2. 通过编写自定义WebControl,在您的用户控件周围构建自己的包装。添加您需要的属性,捕获呈现的用户控件的输出,并使用包含SelectedCatID的键将其插入到HttpContext.Current.Cache中。基本上写你自己的自定义PartialCachingControl。 还有选项3:
  3. 决定缓存并不重要毕竟
+0

'这就是说,如果每页只有一个用户控件,并且应该非常简单。如果每页需要多个用户控件,那么你就不幸运了:'不正确,只需将该指令添加到各个用户控件而不是页面本身。缓存单个用户控件是可能的。 – Hillboy 2014-09-02 18:56:25

+0

以上内容涉及到缓存的用户控件具体。 我在说的是:基于Global.asax覆盖中可用的信息,没有办法推断缓存应该为其创建变体的用户控件的属性值,除非只有一个用户控制每页。 – 2014-09-03 08:38:16

+0

很好的答案谢谢,正是我之后的那种信息。当你完成它的时候,请在这里链接到你的博客文章! – 2014-09-03 11:12:22

0

,我迟到了这里什么与接受的答案和500点赏金奖励。仍然想给我几分钱如何实现这一目标。

它可以在控制本身工作。如果找到,您可以让控件将其自己的输出存储在缓存中,并使用Render方法中的缓存版本。我做了一个非常简单的UserControl来测试。该标记看起来是这样的:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TestUC.ascx.cs" 
    Inherits="Webforms_Test.UserControls.TestUC" %> 
<div> 
    <asp:Label ID="curTime" runat="server"></asp:Label> 
</div> 

它只是包含初始化时被设置为DateTime.Now的标签。后面的代码看起来是这样的:

public partial class TestUC : System.Web.UI.UserControl 
{ 
    private string cachedOutput = null; 
    public bool RenderFromCache = true; // set to false in containing page if this control needs to be re-rendered 

    protected void Page_Load(object sender, EventArgs e) 
    { 
     cachedOutput = HttpContext.Current.Cache["key"] as string; 
     if (cachedOutput == null) 
     { 
      // not found in cache, do the heavy lifting here to setup the control 
      curTime.Text = "UC:" + DateTime.Now.ToString("yy-MM-dd hh:mm:ss"); 
     } 
    } 
    protected void Page_PreRender(object sender, EventArgs e) 
    { 
     if (cachedOutput == null || !RenderFromCache) 
     { 
      RenderFromCache = false; 
      StringBuilder b = new StringBuilder(); 
      HtmlTextWriter h = new HtmlTextWriter(new StringWriter(b)); 
      this.RenderControl(h); 
      cachedOutput = b.ToString(); 
      HttpContext.Current.Cache.Insert("key", cachedOutput, null, DateTime.UtcNow.AddSeconds(10), TimeSpan.Zero); 
      RenderFromCache = true; 
     } 
    } 
    protected override void Render(HtmlTextWriter writer) 
    { 
     if (!RenderFromCache) 
      base.Render(writer); 
     else 
      writer.Write(cachedOutput); 
    } 
} 

在此示例中,如果其输出在高速缓存中找到该控件本身检查,如果是这样的Render方法只写缓存的输出。如果在缓存中找不到,则PreRender方法将正常运行Render方法,并捕获输出并将其存储在缓存中。

在你的情况下,你当然需要更多的逻辑来检查控件上的相关属性,并使用它来检查缓存版本是否存在。

免责声明:这是一个非常简单的测试控件。我还没有试图找出如何使用包含事件处理程序等的控件来完成所有这些工作。因此,请考虑它的价值...

+0

我明白你的意思了。我不相信它会像封装类一样有效。 您的控件仍然会构建整个控件树,以便将其全部扔掉,并提供缓存的html。 PartialCachingControl重写InitRecursive方法,但它的内部标记,所以我们不能使用它。也许OnInit会工作。 – 2014-09-05 20:17:15