2011-12-20 8 views
5

Ho un controllo utente Web, serve alcuni calcoli di dati potenzialmente intensi e vorrei che venisse salvato nella cache in modo che ogni visualizzazione di pagina non ricalcoli i dati . Risiede su pagine viste molto frequentemente quindi è abbastanza importante che funzioni correttamente!ASP.net Come eseguire l'output cache di un webusercontrol su controlli proprietà pubbliche

per il contesto, è utilizzato nel nostro Arcade: http://www.scirra.com/arcade/action/93/8-bits-runner

Clicca sulle statistiche, i dati per i grafici e le statistiche sono generati da questo webusercontrol.

L'inizio del controllo è la seguente:

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) 
    { 

Ora la difficoltà che sto avendo è la cache di output deve essere dipende sia dalla GamID e ChartType.

Questo controllo viene riutilizzato con molte combinazioni diverse di GameID e Tipi, ho bisogno di creare una cache per ognuno di questi, ma sto cercando di capire come farlo.

Per esempio, un gioco arcade potrebbe passare in GameID = 93 e Type = GraphData, un altro potrebbe essere GameID = 41 e Type = TotalPlaysData e un altro potrebbe essere GameID = 93 ma Type = TotalPlaysData. Questi dovrebbero tutti restituire dati diversi e avere differenti cache di output.

Il controllo viene utilizzato nella pagina giochi specie come questo (i parametri sono effettivamente impostati nel codebehind)

<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. 

Qualsiasi aiuto apprezzato! Ho passato un po 'di tempo a guardare online e continua a venire come qualcosa che ho bisogno di risolvere, ma non riesco a capirlo.

Modifica

Edit: Ho provato ad aggiungere questa riga al mio controllo: <% @ OutputCache Duration = "20" VaryByControl = "GameID; Tipo" %>

Ma solo genera l'errore Object reference not set to an instance of an object. sulla riga in cui GameID viene impostato per la prima volta nella pagina ASPX utilizzando il controllo.

risposta

9

Quando un controllo viene recuperato dalla cache di output, non viene istanziato come un'istanza che è possibile modificare; ottieni l'output generato dal controllo, non il controllo stesso. Ad esempio, non puoi impostare proprietà su un controllo memorizzato nella cache dal codice sottostante, come hai detto nella tua domanda. Le proprietà vary-by dovrebbero essere impostate in modo dichiarativo (usando un ExpressionBuilder potrebbe funzionare anche se non l'ho provato).

vedere in codice dietro se un controllo è stato ritirato dalla cache di output, controllare per nulla:

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

Anche con questo avvertimento, uscita di controllo caching è un po 'eccentrico.

Prova questa:

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

L'uscita del controllo è memorizzato nella cache di output associandolo con una certa chiave. Con Shared="true", la chiave di cache è il valore di tutte le proprietà specificate, insieme all'ID del controllo. Senza Shared="true", la chiave cache include anche il tipo di pagina, quindi l'output varia a seconda della pagina, il che non suona come desideri.

Se si utilizza il controllo su più di una pagina, assicurarsi di utilizzare lo stesso ID su ogni pagina, se possibile, poiché l'ID è incluso come parte della chiave per la cache di output. Se non puoi o non usi ID diversi, otterrai una nuova copia dell'output di Control nella cache per ogni ID univoco. Se i controlli con ID diversi hanno sempre valori di proprietà diversi, ciò potrebbe non essere un problema.

In alternativa alla direttiva OutputCache, è possibile impostare un attributo sulla dichiarazione di classe:

[PartialCaching(20, null, "GameID;Type", null, true)] 
public partial class Controls_Arcade_Data_ArcadeChartData : UserControl 
+0

poiché desidera utilizzare il controllo più volte nella stessa pagina, questa soluzione non è valida. non può avere lo stesso ID per più controlli all'interno della stessa pagina. –

+2

È OK utilizzare ID diversi sulla stessa pagina; è sufficiente tenere presente che l'ID fa parte della cache key, quindi è possibile ottenere più copie dello stesso output. Se Type è sempre impostato in base alla posizione del controllo sulla pagina, come nella domanda, potrebbe non essere un problema. – RickNZ

+0

Sembra funzionare come voglio! Testerà ancora un po 'e riferirà. –

3

È necessario adottare le seguenti misure:

1) Aggiungere la seguente direttiva cache di output alla pagina:

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

2) Aggiungere il seguente alla 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; 
     } 
    } 

È possibile ottenere ulteriori informazioni sul metodo GetVaryByCustomString da MSDN e rivedere anche alcune delle altre opzioni di memorizzazione nella cache here.

+0

Sono corretto nel pensare che questo lo memorizzerà nella cache per 6 ore in base all'URL della pagina? I dati saranno su molti URL, voglio solo che memorizzino nella cache in base a 'GameID'. –

+0

@TomGullen: la durata è espressa in secondi, quindi il valore che ho inserito sarebbe valido solo per 10 minuti; Ho regolato il valore corretto (21600). Il modo in cui il metodo è progettato, verrà memorizzato nella cache sull'URL completo, ma è possibile regolare questo comportamento in base alle esigenze nel metodo GetVaryByCustomString se si dispone di parametri aggiuntivi di querystring. –

+0

Tuttavia, non ho parametri di querystring, ho un controllo che ha una proprietà pubblica su cui voglio memorizzare la cache. –

2

creare un oggetto cache nel codice

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

precedente punto della cache sarà sufficiente per il vostro lavoro, ma se si vuole veramente utilizzare cache di output anche provare seguente codice nel codice dietro,

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

Impostazione dei valori per la cache di output delle pagine è lo stesso di manipolare le SetExpires e metodi SetCacheability tramite la proprietà cache.

+0

Grazie, ho ragione nel dire che entrambi questi bit di codice sono destinati al controllo webuser? E anche qual è la differenza tra i due? La cache di output –

+0

memorizza nella cache l'html finale reso in IIS e non ti consente di andare al codice. ma se usi 'HttpRuntime.Cache', memorizzerà nella cache l'oggetto che hai specificato e la richiesta colpirà la pagina effettiva ma non il calcolo nell'oggetto memorizzato nella cache. se si desidera veramente utilizzare la cache di output, è possibile utilizzare la dipendenza dell'oggetto con l'oggetto memorizzato nella cache. –

+0

Sicuramente voglio usare la cache di output perché non voglio che ogni nuovo visitatore abbia rifatto l'oggetto, se otteniamo un gioco popolare con 10.000 riproduzioni in 1 giorno potrebbe essere difficile andare sul server. Quindi penso che la cache di output sia l'opzione migliore. –

0

Un semplice trucco è quello di mettere tutti gli elementi grafici in una nuova pagina che riceve GameID e tipo come parametri querystring, usare la cache di output out-of-the-box per la querystring parametri e il mettere un iframe nella tua pagina. Inoltre è possibile utilizzare la cache del browser e non ottenere mai il server colpito per un po '.

1

So che la mia soluzione potrebbe sembrare molto semplice e forse strana ma l'ho provata e funziona. Devi semplicemente aggiungere questa linea nel tuo UserControl.

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

Nota: ho solo testato il Framework 4.0. Inoltre, se mai dovessi modificare il valore della proprietà in UserControl (MyInt, My String in questo esempio), fallo nell'evento Page_Init.

Qui è tutto il mio codice:

Pagina:

<%@ 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> 

controllo utente:

<%@ 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> 

User Control Code:

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 

Per favore mi mandi postato, io avere altre soluzioni se mai tu desiderio ma sono più complessi. Posso anche pubblicare con C#

+0

Questo non funziona, quando provo a impostare' GameID = TheGame.ID; 'nella pagina ASPX che mantiene il controllo getta un errore di 'Oggetto riferimento non impostato su un'istanza di un oggetto'. quando si tenta di caricare la cache –

+0

Questo in realtà funziona. Sembra che asp.net stia utilizzando le proprietà definite nel tag markup (in questo caso Richard

0

Ok, bene il motivo per cui questo così difficile fare OutputCache lavoro in questo caso è perché non è stato progettato per essere utilizzato con della proprietà, tuttavia funziona molto bene con i parametri QueryString. Quindi la mia prossima soluzione non è la più professionale e probabilmente non la migliore, ma è sicuramente la più veloce e quella che richiede meno modifiche al codice.

Dal momento che funziona meglio QueryString, vi consiglio di mettere il vostro UserControl in una pagina vuota, e Wend mai si desidera utilizzare il UserControl fare un iframe che si collega alla tua pagina con il UserControl con QueryString.

Dove si desidera utilizzare l'UserControl:

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

pagina markup completa, MyArcadeChartData.aspx

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

codice della pagina completa, 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"]; 
} 

prega non che i valori in QueryString possano essere visti dall'utente, per favore non mettere dati sensibili.

Anche io sono consapevole che questa non è la soluzione più professionale, ma è la più semplice da implementare, da quello che so.

saluti e buone feste

+0

Ho appena notato che ivowiblo ha pubblicato la stessa risposta di me, ho semplicemente messo più spiegazioni e dettagli. – plauriola

0

Se ho capito bene, la memorizzazione nella cache non funziona correttamente a causa del modo in cui si hanno le proprietà che forniscono i valori per il controllo, che probabilmente ha a che fare, in parte, con la calcoli che si stanno facendo.

È possibile creare un HttpHandlerFactory che accetta la richiesta, esegue i calcoli se non sono nella cache (inserendo successivamente nella cache), gestisce la scadenza dei valori e quindi passa la richiesta alla pagina. Non sarebbe affatto specifico per il controllo. In questo modo è possibile utilizzare questi valori calcolati in qualsiasi controllo o pagina e non dovrebbe implementare criteri di memorizzazione nella cache che si preoccupano dei propri calcoli.

0

Se non si tratta di dati intensi, hai considerato di archiviarlo nella Sessione come richiesto di memorizzarlo nella cache? Solo un pensiero ...

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

Mi rendo conto che questo non è nella cache, sto solo cercando di essere costruttivo.

Problemi correlati