1

There is parent user control, as seen below.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="TestUserControl.ascx.cs" Inherits="TestUserControl" %>
<%@ Register Src="~/UserControls/ChildUserControl.ascx" TagName="ChildUserControl" TagPrefix="FLI" %>
<div>    
    <FLI:ChildUserControl ID="child1" runat="server"/>    
</div>

The child usecontrol has pulic property MatchDescription, which is set in the Page_Load of the parent control. I want to cache multiple versions of the child control, based on the MatchDescription property.

Problem is, the MatchDescription property cant be set in Page_Load, as the cached copy of the child control is used once its available.

How can i fix this problem?

Thanks!

kmatyaszek
  • 19,016
  • 9
  • 60
  • 65
Rasshme Chawla
  • 1,581
  • 2
  • 13
  • 19
  • Where does the value for `MatchDescription` come from? E.g., does the parent page get it from the Url and then set the property on the child control? – nick_w Oct 17 '12 at 09:13
  • Thanks for having a look ! The value of MatchDescription comes from the Parent user control. No, it doesn't come from the page (not from querystring) – Rasshme Chawla Oct 18 '12 at 09:13
  • No problem ;) Would you be able to provide any more detail on where the parent control gets the value from? It will be easier for me to solve this if I know when and where this piece of data is available. – nick_w Oct 18 '12 at 09:25
  • A service is invoked in the parent user control which returns the MatchDescription of the last match played. – Rasshme Chawla Oct 18 '12 at 10:08

1 Answers1

1

It looks like using GetVaryByCustomString is the way to go here. My proof of concept consisted of the following:

  • WebUserControl.ascx: the test control. It has a single public property MatchDescription.
  • Global.asax: to override the GetVaryByCustomString method.
  • WebForm.aspx: a simple form to host the control.

WebUserControl.ascx

Add the following to the markup on the control:

<%@ OutputCache Duration="120" VaryByParam="none" VaryByCustom="MatchDescription" %>

This specifies the duration (in seconds) to cache the control and VaryByCustom="MatchDescription" specifies the name of the parameter we will be caching on.

WebUserControl.ascx.cs

public partial class WebUserControl1 : System.Web.UI.UserControl
{
    public string MatchDescription { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        object description = this.Context.Application["MatchDescription"];

        if (description != null)
        {
            this.MatchDescription = description.ToString();
        }
        else
        {
            this.MatchDescription = "Not set";
        }

        Label1.Text = "Match description: " + this.MatchDescription;
    }
}

This will check for the existance of the MatchDescription value. Because of the way the code in the parent page works, you should never see "Not set", though in your implementation it may be useful just in case the value is not set.

Global.asax

Add a Global.asax file to your project and add in the following method:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if (custom == "MatchDescription")
    {
        object description = context.Application["MatchDescription"];

        if (description != null)
        {
            return description.ToString();
        }
    }

    return base.GetVaryByCustomString(context, custom);
}

This is the bit that checks for the MatchDescription associated with the cached control. If it is not found the control will be created as normal. context.Application is used because we need a way to communicate the description value between the parent page, the user control and the global.asax file.

WebForm.aspx.cs

public partial class WebForm : System.Web.UI.Page
{
    private static string[] _descriptions = new string[]
    {
        "Description 1",
        "Description 2",
        "Description 3",
        "Description 4"
    };

    protected override void OnPreInit(EventArgs e)
    {
        //Simulate service call.
        string matchDescription = _descriptions[new Random().Next(0, 4)];
        //Store description.
        this.Context.Application["MatchDescription"] = matchDescription;

        base.OnPreInit(e);
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var control = LoadControl("WebUserControl.ascx") as PartialCachingControl;
        this.Form.Controls.Add(control);

        //Indicate whether the control was cached.
        if (control != null)
        {
            if (control.CachedControl == null)
            {
                Label1.Text = "Control was cached";
            }
            else
            {
                Label1.Text = "Control was not cached";
            }
        }
    }
}

Note that in this code I am making/simulating the service call in the OnPreInit method. This is necessary as it occurs in the page lifecycle before the GetVaryByCustomString method.

Keep in mind that if a control has been cached, accessing it in the Page_Load method, for example, will require code of this form:

    if (control is PartialCachingControl &&
        ((PartialCachingControl)control).CachedControl =!= null)
{
    WebUserControl1 userControl = (WebUserControl1)((PartialCachingControl)control).CachedControl;
}

References:

My answer was inspired by: Any way to clear/flush/remove OutputCache?

I found the Pre_Init hint in this question: Output Caching - GetVaryByCustomString based on value set in PageLoad()

This KB article discusses why the PartialCachingControl.CachedControl property can always return null: http://support.microsoft.com/kb/837000

Community
  • 1
  • 1
nick_w
  • 14,758
  • 3
  • 51
  • 71