Как загрузить элемент управления 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
,
Вот так мой .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
Хм, пока нет ответов. Я начал щедрость, надеюсь, это получит немного больше внимания.
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 {}