Url-resolving issue in a "Cacheable-Sharable" UserControl
ResolveUrl and ResolveClientUrl are two methods that help to resolve "~/" prefixed format path to client-browser-usable format. Normally , they take the same effective and just differ in the terminate displaying . Then assuming such a control-holser environment : a UserControl which is designed to shared by a batch of pages; Initially we still find no problems by using either ResolveUrl or ResolveClientUrl to treat url issues in the control , however , if we "cache" the UserControl , mark it with "shared" attribute, and adopt it into an application of multiple pages in different directories , a problem is possible to occur .
Lets assume such a senario :
When building a website , the "top" part is commonly shared by all pages and always displays statically . Considering slightly memory save and performance leverage , a developer encalpusulates such part into a userControl named "Top.ascx" and put it in the same folder of site "Default.aspx" page . Also , considering "different folders' sharing" problem , html links cannot simply use their client url format , so each link in the "Top" usercontrol is re-producted like this :<a href="~/User/Default.aspx" runat="server">User Panel</a>
Note that each server control uses "ResolveClientUrl" to process its Url property value. So the final resolved url may look like "User/Default.aspx" , "../User/Default.aspx" , "../../User/Default.aspx" , based on different host page's location, but never "/User/Default.aspx" ( application runs in root-site ) or "/Application/User/Default.aspx" ( application runs in virtual path "/Application" ) . The latter two results are generated by "ResolveUrl" method.
After link-processing work we add OutputCache declaration to the UserControl to make it cacheable:
<%@ OutputCache Shared="true" Duration="100000" VaryByParam="none" %>
Then put it on the top postion of each "form" in aspx page ( I neglect the "registeration" declaration ) :
<form runat="server">...<cc1:Top runat="server" />
...
</form>
So far , without red-highlighted attribute , there is still no problem when using the control : the "top.ascx" will be correctly and correspondingly processed for the first time visiting of its host page ; however , in such case , each different page owns an independent copy of the same version UserControl in the memory : we enhance the page-processing performance but waste memory . We want "one copy , all share" against the immutable top part. So the existence of "Shared=true" lies in here : one copy of "top part" control is eventually cached in the memory and sharable for all pages inhabiting current application .
Then , the combination of "cache" and "share" operation against a UserControl may bring up following problem :
If we first visit the root default page : /Default.aspx ( in my assumption the Top.ascx also in the root folder of current application ), since it is the first time visiting , Top.acsx will be processed and the "html anchor" control will return an "User/Default.aspx" relative path string; Then we visit an other page : /News/NewsList.aspx ; since the "top.ascx" has been sharely-cached , "top.ascx" UserControl put in the "newslist.aspx" will not process again ; its content directly pours to response stream from memory instead ! So as for the example we still get the link "User/Default.aspx" in the "/News/" context! If user click the link , he will be led to "/News/User/Default.aspx" ---- an nonexistent location !
The solution is simple : In such context , do not use server control and "~/" grammar to set url ; Just use primitive html code and inline method "ResolveUrl" to set url , like this :
<a href='<%=ResolveUrl("~/User/Default.aspx")%>' >User Panel</a>To see an actual , lively sample please visit :
http://www.china-mc.com/ ( China Medical Center )For purpose of performace optimization and memory saving , I design several OutputCache strategies for different part of different pages with the help of UserControl. As you see , the top navigation part and bottom are obvious samples. And the url issue is found in the progress. It is simple to overcome ; However , the conception behind curtain ---- "shared outputCache" is important.
This large portal medical web site is built upon asp.net 3.5 SP1 framework and a lot of fashion technologies overwhelmed by many aspects such as LINQ To Sql , WebForm-based Routing , Control Development , Partial Cache Control Design & Strategy , Global Layout Control , MS Ajax-JQuery etc. are applied to the site. It is an infant. I am the developer & operator of this site and is willing to share my development experience & interesting content relating to my site.