【问题标题】:How to LoadControl a control that uses VaryByControl OutputCache, specifying values for properties如何加载控制使用 VaryByControl OutputCache 的控件,指定属性值
【发布时间】:2011-09-28 07:21:41
【问题描述】:

我有一个应该使用缓存的用户控件,带有VaryByControl.ascx 文件如下所示:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TestControl.ascx.cs" Inherits="mynamespace.TestControl" %>
<%@ OutputCache Duration="10" Shared="true" VaryByControl="Test" %>
<p id="SomeText" runat="server">Nothing</p>

代码隐藏文件中的TestControl 类有一个int Test {...} 属性和一个Page_Load() 事件处理程序,它用以下内容填充SomeText 段落:

SomeText.InnerText = string.Format(@"Test={0} at {1}", Test, DateTime.Now)

我有一个如下所示的.aspx 文件:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestPage.aspx.cs" Inherits="mynamespace.TestPage" %>
<%@ Register TagPrefix="xxx" TagName="TestControl" Src="Controls\TestControl.ascx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <xxx:TestControl Test="6" runat="server" />
    <xxx:TestControl Test="7" runat="server" />
    <hr />
    <asp:PlaceHolder ID="Suport" runat="server" />
</body>
</html>

两个&lt;xxx:TestControl&gt; 标签正确加载TestControl 的实例并将Test 设置为预期值,我可以刷新浏览器几次,我可以看到缓存正常工作。

现在我想用TestControl 的一些实例填充&lt;asp:PlaceHolder ID="Suport" /&gt;,使用不同的Test 值,这都应该受益于适当的缓存。我正在尝试使用LoadControl 方法,但我找不到为Test 属性指定值的方法。我希望存在这样的方法,毕竟加载.aspx 页面的asp.net 代码设法找到适当的缓存控件。我得到的只是PartialCachingControl 的实例,而CachedControl 没有初始化,在运行时呈现的TestControl 显示Test 的默认值为0

这就是我的 .aspx Page_Load() 事件处理程序的样子:

protected void Page_Load(object sender, EventArgs e)
{
    PartialCachingControl tc = (PartialCachingControl) LoadControl(@"Controls\TestControl.ascx");
    if (tc.CachedControl != null)
        ((TestControl)tc.CachedControl).Test = 67;            
    Suport.Controls.Add(tc);
}

编辑

我可以通过缓存整个页面来解决这个问题,但我无法找到解决问题的方法这种方式似乎很奇怪。特别是因为通过 ASPX 文件调用控件按预期工作(证明有办法)。

编辑 2

嗯,目前还没有答案。我开始了一个赏金,希望它得到更多的关注。

【问题讨论】:

    标签: asp.net caching user-controls runtime loadcontrol


    【解决方案1】:

    要让控件参与整个页面生命周期,应将其添加到 Init 事件或 CreateChildControls 方法中,而不是添加到 Load 中。由于 VaryByControl 需要完全限定的控件标识符才能工作,因此必须在页面循环开始之前对其进行初始化。

    类似的东西:

    protected override void OnInit(EventArgs e) {
        var testControl = LoadControl(@"TestControl.ascx");
        testControl.ID =  "TestControl";
        Suport.Controls.Add(testControl);
        base.OnInit(e);
    }
    
    protected override void OnLoad(EventArgs e) {
        TestControl testControl = GetTestControl("TestControl");
        if(testControl != null){ //If it is null it is cached and can not be changed
            testControl.Test = 242;
        }
        base.OnLoad(e);
    }
    
    private TestControl GetTestControl(string name) {
        var control = this.Suport.FindControl(name);
        var partialCachedControl = control as PartialCachingControl;
        if(partialCachedControl != null) {
            control = partialCachedControl.CachedControl;
        }
        return control as TestControl;
    }
    

    由于每个控件都缓存了输出,因此在清除缓存之前无法更改控件。如果要更改值并重新生成内容,则必须清除缓存或创建新控件(使用新 ID)。清除缓存的一种方法是改用 VaryByCustom 并生成一个缓存键,如果您的测试值发生变化,该键也会发生变化。

    还记得在您的测试控件上实现 INamingContainer 接口,以避免不同对象之间的命名冲突。为此,只需将接口添加到控件,如下所示:

    public class TestControl: WebControl, INamingContainer {}
    

    【讨论】:

    • 不起作用: 如果TestControl.ascx 启用缓存(使用@OutputCache)然后LoadControl 返回一个System.Web.UI.PartialCachingControl 对象,所以转换为TestControl失败,引发 InvalidCastException。正如我在 #1 编辑中提到的,两天前,我确实想要缓存整个页面,如果这就是您所说的“让框架负责缓存”的话。
    • 我现在实际上在这里创建了自己的测试页面,但它不起作用。我显然是记错了。对不起。我现在已经编辑了我的帖子,该代码对我有用。
    • 这仍然不可能工作,因为OnLoad 被称为之前 CreateChildControls。撤销了反对票,因为我认为你在做某事。
    • 嗯,你确定吗?对我来说,在 OnLoad 之前调用 CreateChildControl。但是,如果我将代码移至 OnInit,它也可以工作。
    • 啊,我想你误解了 VarByControl 属性,它不会告诉缓存改变控件上的属性,而是改变页面上控件的 ID。这是来自 MSDN 的文本:“VaryByControl 属性设置为完全限定的控件标识符,其中标识符是从顶级父控件开始并以美元符号 ($) 字符分隔的控件 ID 的串联。”。
    【解决方案2】:

    我认为您误解了 VarByControl 属性,它不会告诉缓存更改控件上的属性,而是更改页面上控件的 ID。 Here is the text from MSDN

    VaryByControl 属性设置为完全限定的控件标识符,其中标识符是从顶级父控件开始并以美元符号 ($) 字符分隔的控件 ID 的串联。

    在您的情况下,您可以设置 VaryByCustom 而不是 VaryByControl 并从 Test-property-value 生成一个缓存键,并在它发生变化时对其进行更改。

    【讨论】:

      【解决方案3】:

      您必须交换 2 行代码才能使您的代码正常工作:

      PartialCachingControl tc = (PartialCachingControl) LoadControl(@"Controls\TestControl.ascx");
      Suport.Controls.Add(tc);
      if (tc.CachedControl != null)
          ((TestControl)tc.CachedControl).Test = 67;            
      

      一旦你添加了控件,缓存的控件就会被初始化。

      例如

      【讨论】:

      • 这是我丢失的信息,必须在缓存控件对象可用之前添加控件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      相关资源
      最近更新 更多