Now I've created a function
/// <summary>
///
/// </summary>
/// <param name="page"></param>
/// <param name="cssFileHref">e.g. "~/StyleSheet.css"</param>
/// <returns></returns>
public static HtmlLink AddStyleSheetLink(this Page page, string cssFileHref)
{
if (page.Header == null) { throw new NullReferenceException("page.Header is null"); }
HtmlLink link = new HtmlLink();
link.Href = cssFileHref;
link.Attributes.Add("rel", "stylesheet");
link.Attributes.Add("type", "text/css");
page.Header.Controls.Add(link);
return link;
}
and called it from markup aspx.
<% //this.AddHeadItems();CSSHelper.AddStyleSheetLink(this,"MyStylesFile.css?v="+Utility.AssemblyVersionNumber()); %>
Similar function in VB has been described in StyleSheetsManage class for DotNetNuke post.
Note that I intentionally calling it from markup instead of code behind to be able manually change URL(e.g to ?v57=") without new version rebuild to force refresh of CSS file in client browsers.
Initially it failed with the error:
Additional information: The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).
, but I was able to delete code render blocks out off HEAD block.
Then I found, that if I am calling AddStyleSheetLink after <HEAD runat="server"> block, the call has no effect and link to CSS file is not inserted.
But when I've put AddStyleSheetLink before HEAD, it works as expected
<% //this.AddHeadItems();
CSSHelper.AddStyleSheetLink(this,"MyStylesFile.css?v="+Utility.AssemblyVersionNumber()); %>
<HEAD runat="server">
....
</HEAD>
and generates desired html: