Как загрузить элемент управления ControlControl, который использует VaryByControl OutputCache, указав значения для свойств

У меня есть пользовательский элемент управления, который должен использовать кеширование, с 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>

Два <xxx:TestControl> теги правильно загружают экземпляры TestControl с Test Установив ожидаемое значение, я могу несколько раз обновить браузер и увидеть, как кеш правильно выполняет свою работу.

Теперь я хотел бы заполнить <asp:PlaceHolder ID="Suport" /> с некоторыми случаями TestControl, используя разные Test ценности, которые должны выиграть от правильного кэширования. Я пытаюсь использовать LoadControl метод, но я не могу найти способ указать значение для Test имущество. Я ожидаю, что такой метод существует, в конце концов asp.net загрузка кода .aspx странице удается найти правильный кешированный элемент управления. Все, что я получаю, это экземпляр PartialCachingControl без CachedControl инициализируется и во время выполнения отображается TestControl шоу Test имеет значение по умолчанию 0,

Вот так мой .aspxPage_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

Хм, пока нет ответов. Я начал щедрость, надеюсь, это получит немного больше внимания.

3 ответа

Решение

Я думаю, что вы неправильно поняли свойство VarByControl, оно говорит не кэшу об изменении свойства элемента управления, а об идентификаторе элементов управления на странице. Вот текст из MSDN:

Свойство VaryByControl устанавливается для полностью определенных идентификаторов элемента управления, где идентификатор представляет собой объединение идентификаторов элемента управления, начиная с родительского элемента управления верхнего уровня и ограниченного знаком доллара ($).

В вашем случае вы можете установить VaryByCustom вместо VaryByControl и сгенерировать ключ кеша из значения свойства Test и изменить его, если он изменится.

Вы должны поменять 2 строки, чтобы ваш код работал:

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

Как только вы добавляете элемент управления, кэшированный элемент управления инициализируется.

НАПРИМЕР

Чтобы элемент управления участвовал в жизненном цикле полной страницы, его нужно добавить в событие Init или метод CreateChildControls, а не добавлять его при загрузке. Поскольку для работы 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;
}

Поскольку выходные данные кэшируются для каждого элемента управления, вы не можете изменить элемент управления, пока кэш не будет очищен. Если вы хотите изменить значение и восстановить контент, вам нужно либо очистить кеш, либо создать новый элемент управления (с новым идентификатором). Один из способов очистить кеш - использовать вместо него VaryByCustom и генерировать ключ кеша, который изменяется при изменении значения Test.

Также не забудьте внедрить интерфейс INamingContainer в свой тестовый элемент управления, чтобы избежать конфликтов имен между различными объектами. Для этого просто добавьте интерфейс к элементу управления, например так:

public class TestControl: WebControl, INamingContainer {}
Другие вопросы по тегам