使用webusercontrol获取输出缓存以在ASP.net中工作

时间:2014-08-27 11:10:41

标签: asp.net caching outputcache webusercontrol

我有webusercontrol个公开int属性SelectedCatID。我在其他页面和其他控件中使用此控件,如下所示:

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

如何根据SelectedCatID输出缓存此控件?我尝试的一切都失败了。

我最接近的是让它进行缓存,但它在SelectedCatID上不会发生变化,只有在缓存过期之前才会选择相同的菜单项。如果没有缓存,控件将按预期工作。

3 个答案:

答案 0 :(得分:3)

我弄清楚为什么你最初使用的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个usercontrol,则可以使用VaryByCustom方法。为了方便起见,您可以编写一个返回该页面属性值的接口,并在托管用户控件的每个页面上实现它,例如:

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

    在Global.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 Duration =&#34; 180&#34; VaryByCustom是=&#34; INumberProvider&#34;的VaryByParam =&#34;无&#34;共享=&#34;真&#34;

    如果每页只有一个用户控件,那应该非常简单。如果每页需要多个用户控件,那么运气不佳:

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

答案 1 :(得分:0)

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

现在存储你&lt;%#CatIDToSelect%&gt;作为参数ex?SelectedCatID = 12 现在你是Page或UserControl取决于你想要缓存的内容将输出缓存,具体取决于Request.Param [“SelectedCatID”]等于的内容。

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

这会在您要缓存的页面/ usercontrol上进行:

<%@ 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;
}

答案 2 :(得分: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方法并捕获输出并将其存储在缓存中。

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

免责声明:这是一个非常简单的测试控件。我没有试图弄清楚如何使用包含事件处理程序等的控件来完成所有这些工作。所以请把它当作它的价值......