Tuesday, August 05, 2008

Javascript script blocks relative paths in ASP.Net

ASP.Net 2.0 added a very useful thing, the '~' sign, which indicates that a path is relative to the application directory. Since the application itself should be indifferent to its name, this little thing comes in useful when trying to set the location of user controls, style sheets and so on. The problem is that this feature only applies to user controls. That is not a problem for most tags, since even a link tag can be set as a user control with a runat=server attribute.

The problem comes when trying to set the location of javascript script blocks. A script block with runat=server must be a server code block by definition, i.e. C# or VB, whatever the site language is set to. One of the solutions often used to solve this is to use a code block inside the src attribute of the javascript block like this:
<script language="Javascript" type="text/javascript" 
src='<% =ResolveUrl("~/scripts/myScript.js")%>'></script>
.

But this is still a nasty issue, because of the dreaded The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>). error. As in the post I linked to, the solution for this is to place all external script blocks within a server control like a PlaceHolder or a even a div with the runat=server attribute set. The drawback to this solution is that you can't do that in the <head> section of the HTML output.

The other solution is to use from within the server code the ScriptManager.RegisterClientScriptInclude method to add the script programatically to the page. While this is elegant, it also defeats the purpose of the aspx page, that is to separate content from code.

3 comments:

Des Courtney said...

This is an ugly little issue that was messing up our use of Master Pages in our internal system for the last year or so. I ultimately solved the problem by creating a custom control that takes the src path and uses the Page_PreRender step to "transplant" the properties of the control to the page's header using code similar to that discussed here. This ended up being useful for CSS links as well, since we could now place URL to external CSS in the body (read, in webapp page contents) and the control would put them in the header where they belonged...

Siderite said...

Thank you for sharing this solution. So in other words you used a user control instead of a script tag? Wish I'd thought of that. It sounds mighty elegant...

nic said...

Thanks this helped me.