ASP.net Как вывести кеш webusercontrol на элементы управления публичными свойствами - PullRequest
5 голосов
/ 20 декабря 2011

У меня есть пользовательский веб-элемент управления, он обслуживает некоторые потенциально интенсивные вычисления данных, и я хотел бы, чтобы он выводился в кэш-память, чтобы при каждом просмотре страницы данные не пересчитывались.Он находится на очень часто просматриваемых страницах, поэтому очень важно, чтобы он работал правильно!

Для контекста он используется в нашей аркаде: http://www.scirra.com/arcade/action/93/8-bits-runner

Нажмите на статистику, данныеграфы и статистика генерируются из этого webusercontrol.

Запуск элемента управления выглядит следующим образом:

public partial class Controls_Arcade_Data_ArcadeChartData : System.Web.UI.UserControl
{
    public int GameID { get; set; }
    public Arcade.ChartDataType.ChartType Type { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {

Теперь сложность, с которой я столкнулся, заключается в том, что кэш вывода должен зависетькак для GamID, так и для ChartType.

Этот элемент управления повторно используется со многими различными комбинациями GameID и Types, мне нужно создать кеш для каждого из них, но я пытаюсь выяснить, как это сделать..

Например, одна аркадная игра может пройти в GameID = 93 и Type = GraphData, другая может быть GameID = 41 и Type = TotalPlaysData, а другая может быть GameID = 93, но Type = TotalPlaysData.Все они должны возвращать разные данные и иметь разные выходные кэши.

Элемент управления используется на странице игр примерно так (параметры фактически заданы в коде)

<div>Total Plays:</div>
<div class="count"><Scirra:ArcadeChartData runat="server" GameID="93" Type="TotalPlays" /></div>
<br /><br />
<div>Total Guest Plays:</div>
<div class="count"><Scirra:ArcadeChartData runat="server" GameID="93" Type="TotalGuestPlays" /></div>

etc.

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

Редактировать

Редактировать: IЯ пытался добавить эту строку в мой элемент управления: <% @ OutputCache Duration = "20" VaryByControl = "GameID; Тип"%>

Но он просто выдает ошибку Object reference not set to an instance of an object. в строке, где GameIDустанавливается впервые на странице ASPX с помощью элемента управления.

Ответы [ 8 ]

9 голосов
/ 24 декабря 2011

Когда элемент управления извлекается из выходного кэша, он не создается как экземпляр, которым вы можете манипулировать;вы просто получаете результат, сгенерированный Control, а не сам Control.Например, вы не можете установить свойства кэшированного элемента управления из кода, как вы сказали в своем вопросе.Свойства var-by должны быть установлены декларативно (использование ExpressionBuilder также может работать, хотя я этого не пробовал).

Чтобы увидеть в коде, был ли элемент управления получен из выходного кэша, проверьте наличиеnull:

if (this.YourControlID != null) // true if not from cache
{
    // do stuff
}

Даже с учетом этого предостережения кэширование выходных данных управления немного странно.

Попробуйте:

<%@ OutputCache Duration="20" VaryByControl="GameID;Type" Shared="true" %>

Вывод элементов управления сохраняется ввыходной кеш, связав его с определенным ключом.При Shared="true" ключ кэша является значением всех указанных свойств вместе с идентификатором элемента управления.Без Shared="true" ключ кеша также включает тип страницы, поэтому вывод будет зависеть от страницы - что не похоже на то, что вы хотите.

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

В качестве альтернативы директиве OutputCache вы можете установить атрибут в объявлении класса:

[PartialCaching(20, null, "GameID;Type", null, true)]
public partial class Controls_Arcade_Data_ArcadeChartData : UserControl
3 голосов
/ 20 декабря 2011

Вам необходимо выполнить следующие шаги:

1) Добавить следующую директиву кэша вывода на страницу:

<%@ OutputCache Duration="21600" VaryByParam="None" VaryByCustom="FullURL" %>

2) Добавить следующее в global.asax:

    public override string GetVaryByCustomString(HttpContext context, string arg)
    {
        if (arg.Equals("FullURL", StringComparison.InvariantCultureIgnoreCase)
        {
            // Retrieves the page
            Page oPage = context.Handler as Page;

            int gameId;

            // If the GameID is not in the page, you can use the Controls 
            // collection of the page to find the specific usercontrol and 
            // extract the GameID from that.

            // Otherwise, get the GameID from the page

            // You could also cast above
            gameId = (MyGamePage)oPage.GameID;

            // Generate a unique cache string based on the GameID
            return "GameID" + gameId.ToString();
        }
        else
        {
            return string.Empty;
        }
    }

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

2 голосов
/ 22 декабря 2011

создать объект кеша в коде

HttpRuntime.Cache.Insert("ArcadeChartData" + GameID + Type, <object to cache>, null, System.Web.Caching.Cache.NoAbsoluteExpiration,new TimeSpan(0, 0, secondsToCache),CacheItemPriority.Normal, null);

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

Response.AddCacheItemDependency("ArcadeChartData" + GameID + Type);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);

Установка значений для кэша вывода страницы аналогична манипулированию методы SetExpires и SetCacheability через свойство Cache.

1 голос
/ 23 декабря 2011

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

<%@ OutputCache Duration="10" VaryByParam="none" %>

Примечание. Я тестировал только Framework 4.0. Также, если вам когда-либо понадобится изменить значение свойства в UserControl (MyInt, My String в этом примере), сделайте это в событии Page_Init.

Вот весь мой код:

Страница:

<%@ Page Title="Home Page" Language="vb" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="MyWebApp._Default" %>
<%@ Register Src="~/UserControl/MyUserControl.ascx" TagPrefix="uc" TagName="MyUserControl" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <uc:MyUserControl ID="uc1" MyInt="1" MyString="Test"  runat="server" />
    <hr />
    <uc:MyUserControl ID="uc2" MyInt="3" MyString="Test"  runat="server" />
    <hr />      
    <uc:MyUserControl ID="uc3" MyInt="1" MyString="Testing" runat="server" />
</asp:Content>

Контроль пользователя:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="MyUserControl.ascx.vb" Inherits="MyWebApp.MyUserControl" %>
<%@ OutputCache Duration="10" VaryByParam="none" %>

<div style="background-color:Red;">
    Test<br />
    <asp:Label ID="lblTime" ForeColor="White" runat="server" />
</div>

Код контроля пользователя:

Public Class MyUserControl
    Inherits System.Web.UI.UserControl

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Debug.Write("Page_Load of {0}", Me.ID)
        Dim oStrBldr As New StringBuilder()
        For i As Integer = 1 To Me.MyInt
            oStrBldr.AppendFormat("{0}: {1} - {2} at {3}<br />{4}", Me.ID, i, Me.MyString, Date.Now.ToLongTimeString(), System.Environment.NewLine)
        Next
        Me.lblTime.Text = oStrBldr.ToString()
    End Sub


    Public Property MyInt As Integer
    Public Property MyString As String

End Class

Пожалуйста, держите меня в курсе, у меня есть другие решения, если хотите, но они более сложные. Я также могу опубликовать с C #

0 голосов
/ 29 декабря 2011

Если это не требует больших объемов данных, рассматривали ли вы вопрос об их сохранении в сеансе, в отличие от кэширования? Просто мысль ...

Arcade.ChartDataType.ChartType Type;
string GameKey = GameId + Type.toString();
storedData = callCalculation(GameId,Type);
Session[GameKey] = storedData;

Я понимаю, что это не в кеше, я просто пытаюсь быть конструктивным.

0 голосов
/ 28 декабря 2011

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

Вы можете создать HttpHandlerFactory, который принимает запрос, выполняет ваши вычисления, если они не находятся в кэше (затем вставляет в кэш), обрабатывает истечение значений и затем передает запрос на страницу. Это не будет зависеть от контроля вообще. Таким образом, вы можете использовать эти вычисленные значения на любом элементе управления или странице, и вам не придется реализовывать политики кэширования, которые беспокоятся о своих собственных вычислениях.

0 голосов
/ 26 декабря 2011

Хорошо, причина, по которой это так трудно заставить OutputCache работать в этом случае, заключается в том, что он не предназначен для использования с Свойством , однако он очень хорошо работает с QueryString параметры.Поэтому мое следующее решение не самое профессиональное и, вероятно, не самое лучшее, но оно определенно самое быстрое и требует меньше изменений кода.

Поскольку он работает лучше всего QueryString , я рекомендую вам поместить UserControl на одну пустую страницу, и мы всегда хотим использовать UserControl создайте iframe, который ссылается на вашу страницу с помощью UserControl с QueryString .

Где вы хотите использовать свой UserControl:

<iframe src="/MyArcadeChartData.aspx?GameID=93&Type=TotalPlays"></iframe>

Fullразметка страницы, MyArcadeChartData.aspx

<%@ Page ... %>
<%@ OutputCache Duration="20" VaryByParam="GameID;Type" %>
<Scirra:ArcadeChartData ID="MyUserControlID" runat="server />

Полный код страницы, MyArcadeChartData.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
    //TODO: Put validation here
    MyUserControlID.GameID = (int)Request.QueryString["GameID"];
    MyUserControlID.Type = (YourEnum)Request.QueryString["Type"];
}

Обратите внимание, что значения в QueryString могут быть просмотрены пользователем, пожалуйста, неположите конфиденциальные данные.

Также я знаю, что это не самое профессиональное решение, но оно наиболее простое в реализации, насколько я знаю.

С уважением и счастливых праздников

0 голосов
/ 23 декабря 2011

Один простой трюк - поместить всю графику на новую страницу, получая GameId и Type в качестве параметров строки запроса, использовать готовый кэш вывода для параметров строки запроса и вставить iframe на свою страницу.Также вы можете использовать кеш браузера и ни разу не получить доступ к серверу.

...