Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.net How to output cache a webusercontrol on controls public properties

I have a web user control, it serves some potentially intensive data calculations and I would like it to be output cached so that each page view doesn't recalculate the data. It resides on very frequently viewed pages so it's quite important I get it working right!

For context, it's used on our arcade: http://www.scirra.com/arcade/action/93/8-bits-runner

Click on stats, the data for the graphs and stats are generated from this webusercontrol.

The start of the control is as follows:

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

Now the difficulty I'm having is the output cache needs to be dependant on both the GamID and the ChartType.

This control is re-used with many different combinations of GameID's and Types, I need it to create a cache for each of these but am struggling to find out how to do this.

For example, one arcade game might pass in GameID = 93 and Type = GraphData, another might be GameID = 41 and Type = TotalPlaysData and another might be GameID = 93 but Type = TotalPlaysData. These should all return different data and have different output caches.

The control is used on the games page sort of like this (the parameters are actually set in the 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.

Any help appreciated! I've spent a while looking online and it's kept coming up as something I need to solve but can't figure this one out.

Edit

Edit: I've tried adding this line to my control: <%@ OutputCache Duration="20" VaryByControl="GameID;Type" %>

But it just throws the error Object reference not set to an instance of an object. on the line where GameID is being set for the first time on the ASPX page using the control.

like image 534
Tom Gullen Avatar asked Dec 20 '11 00:12

Tom Gullen


People also ask

How output cache works in MVC?

The output cache enables you to cache the content returned by a controller action. That way, the same content does not need to be generated each and every time the same controller action is invoked. Imagine, for example, that your ASP.NET MVC application displays a list of database records in a view named Index.

How do I cache an ASPX page?

Page Output Caching A page is enabled for caching using the @OutputCache directive. This directive is written at the top of the page which is to be cached. The code below shows the code in the hold to cache a web page for 60 seconds.

How caching is done in ASP.NET explain with example?

To manually cache application data, you can use the MemoryCache class in ASP.NET. ASP.NET also supports output caching, which stores the generated output of pages, controls, and HTTP responses in memory. You can configure output caching declaratively in an ASP.NET Web page or by using settings in the Web. config file.

Where is ASP.NET cache stored?

The cached data is stored in server memory. Class Caching : Web pages or web services are compiled into a page class in the assembly, when run for the first time. Then the assembly is cached in the server.


2 Answers

When a Control is retrieved from the output cache, it's not instantiated as an instance that you can manipulate; you just get the output the Control generated, not the Control itself. For example, you can't set properties on a cached Control from code behind, as you said in your question. The vary-by properties should be set declaratively (using an ExpressionBuilder might also work, though I haven't tried it).

To see in code behind whether a control has been retrieved from the output cache, check for null:

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

Even with that caveat, Control output caching is a bit quirky.

Try this:

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

The output of the Control is stored in the output cache by associating it with a certain key. With Shared="true", the cache key is the value of all specified properties, together with the Control's ID. Without Shared="true", the cache key also includes the Page type, so the output would vary by Page -- which doesn't sound like what you want.

If you use the Control on more than one page, be sure to use the same ID on each page if you can, since the ID is included as part of the key for the output cache. If you can't or don't use different IDs, you will get a new copy of the Control's output in the cache for each unique ID. If the Controls with different IDs always have different property values anyway, that may not be an issue.

As an alternative to the OutputCache directive, you can set an attribute on the class declaration:

[PartialCaching(20, null, "GameID;Type", null, true)]
public partial class Controls_Arcade_Data_ArcadeChartData : UserControl
like image 78
RickNZ Avatar answered Sep 27 '22 23:09

RickNZ


You need to take the following steps:

1) Add the following output cache directive to the page:

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

2) Add the following to 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;
        }
    }

You can get more information on the GetVaryByCustomString method from MSDN and also review some of the other caching options here.

like image 40
competent_tech Avatar answered Sep 27 '22 21:09

competent_tech