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