Получите кеш вывода для работы в ASP.net с помощью webusercontrol

У меня webusercontrol с общедоступным int свойством SelectedCatID. Я использую этот элемент управления на других страницах и в других элементах управления следующим образом:

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

Как мне вывести кеш этого элемента управления на основе SelectedCatID? Все, что я пробовал, терпит неудачу.

Самое близкое, что я получил, - это поместить его в кеш, но это не меняется, если SelectedCatID остается выбранным тот же пункт меню, пока не истечет срок действия кеша. Без кеширования элемент управления работает должным образом.


person Tom Gullen    schedule 27.08.2014    source источник
comment
Атрибут VaryByControl должен соответствовать идентификатору пользовательского элемента управления для кеширования, а не только произвольному свойству элемента управления. Если вы проверите, что элемент управления существует в коде позади, а затем установите переменную, которая будет использоваться вашим NewStore:LeftMenuLinks пользовательским элементом управления, будет ли это работать?   -  person Justin    schedule 29.08.2014
comment
У вас есть версия SelectedCatID = ‹% # SelectedCatID%› в элементе управления с привязкой к данным или она просто привязана к свойству класса страницы? Какая связь между SelectedCatID и SelectedMenu? Или это просто опечатка?   -  person Menno van den Heuvel    schedule 02.09.2014
comment
@menno опечатка, исправляем!   -  person Tom Gullen    schedule 02.09.2014
comment
Все, что я пытаюсь сделать, это кэш вывода на основе общедоступных свойств элемента управления, и я просто не могу понять, как это сделать. Вопрос не привлекает особого внимания, поэтому я отредактирую его, чтобы было понятнее.   -  person Tom Gullen    schedule 02.09.2014


Ответы (3)


Я понял, почему подход VaryByControls, который вы использовали изначально, не работает. К сожалению, вы исключили его из своего вопроса, поэтому мои исследования по этому поводу просто должны быть включены в сообщение в блоге. Обновление: рассматриваемое сообщение в блоге: http://tabeokatech.blogspot.be/2014/09/outputcache-on-user-controls.html.

Короче говоря, VaryByControls является своего рода сокращением для VaryByParams и ничего не делает для свойств: он смотрит только на значения POST. Тот факт, что он когда-либо работал для свойств со статическим значением, кажется ошибкой - любая строка в VaryByControls заставила бы эту часть работать. Принятый ответ на этот вопрос неверен: Варьируйте в зависимости от свойств элемента управления, используя Частичное кэширование в ASP.NET.

Не существует встроенного способа изменения значений свойств элемента управления.

В любом случае это не имело бы смысла, потому что пользовательские элементы управления должны быть созданы, чтобы иметь значения свойств, и вы хотите избежать их создания, вместо кеширования их отображаемой разметки - кэшированные поля пользовательских элементов управления имеют значение NULL в коде программной части, если кэшированная разметка обслуживается для их. Это работает путем внедрения PartialCachingControl на страницу вместо фактического пользовательского элемента управления. Этот PartialCachingControl проверяет кеш и создает элемент управления только в том случае, если кэшированная версия не существует.

Что касается работы, я вижу два варианта:

  1. Если у вас есть только 1 пользовательский элемент управления на страницу, вы можете использовать подход 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 = "180" VaryByCustom = "INumberProvider" VaryByParam = "None" Shared = "true"

    Это если у вас есть только один пользовательский элемент управления на странице, и это должно быть довольно просто. Если вам нужно более одного пользовательского элемента управления на странице, вам не повезло:

  2. Создайте собственную оболочку вокруг вашего пользовательского элемента управления, написав собственный WebControl. Добавьте необходимые свойства, зафиксируйте вывод визуализированного пользовательского элемента управления и вставьте его в HttpContext.Current.Cache с ключом, который включает SelectedCatID. В основном напишите свой собственный PartialCachingControl. Также есть вариант 3:
  3. Решите, что кеширование не так уж и важно
person Menno van den Heuvel    schedule 02.09.2014
comment
That's if you only have one user control per page, and should be pretty straightforward. If you need more than one user control per page you're out of luck: Неверно. Вы просто добавляете директиву к различным пользовательским элементам управления, а не к самой странице. возможно кеширование отдельного пользовательского элемента управления. - person Hillboy; 02.09.2014
comment
Вышесказанное относится конкретно к кешированию пользовательских элементов управления. Я говорю: на основе информации, доступной в переопределении Global.asax, невозможно вывести значение свойства пользовательского элемента управления, для которого предполагается создать вариант кеша, если только один из пользователей элементов управления на странице. - person Menno van den Heuvel; 03.09.2014
comment
Отличный ответ, спасибо, именно та информация, которую я искал. Пожалуйста, сделайте ссылку на свой блог здесь, когда вы это сделаете! - person Tom Gullen; 03.09.2014

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

Теперь сохраните ваш ‹% # CatIDToSelect%> в качестве параметра 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;
}
person Hillboy    schedule 02.09.2014
comment
Взгляните на этот pastebin: pastebin.com/NLmZkfP9 Выдает ошибку CS0115: 'Controls_Blog_LatestEntries.GetVaryByCustomString(System.Web.HttpContext, string)': no suitable method found to override. Кэш определен как <%@ OutputCache duration="120" varybyparam="None" varybycustom="SelectedBlogID" %>. Я понял из Google, что это предназначено для использования в global.asax, но это мне не помогает. Мне нужен способ кэширования элемента управления на основе свойств, переданных в iut - person Tom Gullen; 02.09.2014
comment
Хорошо, поэтому я протестировал, похоже, вам не нужен ([OutputCache (CacheProfile = CacheProfile)]. И работает после обновления страницы. Я тестировал страницу, которая показывает точное время (включая секунды) после второго обновления, секунды больше не меняют время будет постоянно, пока не истечет срок действия. Просто следите за изменениями, которые я внес в сообщение. - person Hillboy; 02.09.2014
comment
мой тестовый код для просмотра (4 файла): pastebin.com/6v10bSgg pastebin.com/QFNXE7Z1 pastebin.com/Jbfuwywf pastebin.com/AXC2vT95 - person Hillboy; 02.09.2014

Я опаздываю на вечеринку с принятым ответом и наградой в 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 в обычном режиме, захватит вывод и сохранит его в кеше.

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

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

person user1429080    schedule 05.09.2014
comment
Я понимаю, о чем вы говорите. Я не уверен, что это будет почти так же эффективно, как класс-оболочка. Ваш элемент управления по-прежнему будет строить все дерево элементов управления, чтобы все это выбросить и обслуживать кешированный HTML. PartialCachingControl переопределяет метод InitRecursive, но он помечен как внутренний, поэтому мы не можем его использовать. Может, OnInit сработает. - person Menno van den Heuvel; 06.09.2014