My musings about .NET and what not

The Controls Collection Cannot Be Modified Because the Control Contains Code Blocks

If you're using Master Pages in ASP.NET and trying to resolve or references in the page head, you may have run into this this show-stopper. If so, here's why it's happening, and here's an easy way to fix it.

If you've worked with ASP.NET Master Pages, you've no doubt taken advantage of automatic URL re-basing within the HtmlHead control. This bit of ASP.NET magic helps assure that a content page has access to the correct resources:

<head id="head1" runat="server">
   <title>My Pagetitle>
   <link href="css/common.css" rel="stylesheet" type="text/css" />
head>

When you add the runat="server" attribute to the tag, the runtime treats it as an HtmlHead control. The HtmlHead control has the ability to parse child controls contained withing it, so that when a content page is rendered, the URL in the href attribute points to the correct file. Pretty sweet.

The Problem

Now, let's say you also want to place a reference to an external JavaScript file in the , so you do this:

<head id="head1" runat="server">
   <title>My Pagetitle>
   <link href="css/common.css" rel="stylesheet" type="text/css" />
   <script type="text/javascript" src="javascript/leesUtils.js">script>
head>

Naturally, you might assume that URL re-basing will help you out here, but you'd be mistaken. Unfortunately, the runtime doesn't automatically re-base URLs in or tags, so any page not in the same directory as your master page won't find your script or CSS files. Bummer.

Soooo... you figure if HtmlHead won't resolve your URL automatically, you'll wrestle that sucker manually by using the Control.ResolveUrl method. ResolveUrl can take a URL that is relative to the root of the application and correct it for the current request path. You'd then use a code block to substitute the correct URL at runtime:

<head id="head1" runat="server">
   <title>My Pagetitle>
   <link href="css/common.css" rel="stylesheet" type="text/css" />
   <script type="text/javascript" src="<%= ResolveUrl("~/javascript/leesUtils.js") %>">script>
head>

But then, when you run the page, you get the following System.Web.HttpException :

The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).

Ouch. As we can see, page headers don't play nice with code blocks. That's no fun. What to do?

The Solution

I've seen various solutions for this published before. Some will tell you to simply move the code block to the form or to a ContentPlaceHolder, which requires you to move the tag out of the header (and which will fail if you populate the placeholder in a content page). Other solutions involve dynamically creating elements and adding them to the HtmlHead.Controls collection at runtime. However, I've come up with something I find a lot easier and more straightforward -- while leaving the tag in the header where it belongs.

First, start the code block with <%#  instead of <%=  :

<head id="head1" runat="server">
   <title>My Pagetitle>
   <link href="css/common.css" rel="stylesheet" type="text/css" />
   <script type="text/javascript" src="<%# ResolveUrl("~/javascript/leesUtils.js") %>">script>
head>

This changes the code block from a Response.Write code block to a databinding expression. Since <%# ... %> databinding expressions aren't code blocks, the CLR won't complain. Then in the code for the master page, you'd add the following:

protected void Page_Load(object sender, EventArgs e)
   {
      Page.Header.DataBind();    
   }

The DataBind method evaluates all the databinding expression(s) in your header at load time, and you're good to go. No muss, no fuss, no ring around the collar.

Subscribe to this blog for more cool content like this!

kick it on DotNetKicks.com

shout it on DotNetShoutOut.com

vote it on WebDevVote.com

Bookmark / Share

    » Similar Posts

    1. Nested ListViews and More - Working with Databound Controls Inside the ListView
    2. Building a TweetThis Extension with Automatic Bit.ly for Graffiti CMS
    3. Resetting the Page Index in a ListView

    » Trackbacks & Pingbacks

    1. You've been kicked (a good thing) - Trackback from DotNetKicks.com

      The Controls Collection Cannot Be Modified... — November 25, 2008 1:25 PM
    2. Pingback from How to add a script file programtically?

      How to add a script file programtically? — February 25, 2009 4:49 PM
    3. Pingback from How to add a script file programtically?

      How to add a script file programtically? — February 25, 2009 6:01 PM
    Trackback link for this post:
    http://leedumond.com/trackback.ashx?id=26

    » Comments

    1. rajesh avatar

      Too good dear , i was facing this problem from 2 days....really gr8 solution

      rajesh — December 22, 2008 3:24 AM
    2. Osiris avatar

      Beautiful. Just the answer I've been serching for. Congrats!

      Osiris — January 14, 2009 8:23 PM
    3. madey avatar

      I'm having this similar problem too. Great work!

      madey — March 10, 2009 9:39 PM
    4. vij avatar

      <%#...%> works only when tried to access a control, in my case i am trying this to access a public variable declared in code behind of asp.net, so replacing # is giving me error as such i am bound to use <# =...% > ..........can someone help me?

      vij — March 12, 2009 3:06 AM
    5. minimi avatar

      THANKS!!!!!!!!!!!

      the dataBind() method saved me

      minimi — March 18, 2009 12:11 PM
    6. sharath avatar

      I have a similar problem when i was using Master pages in VS2008. This is the correct and simple solution

      Thanks

      sharath — May 25, 2009 9:09 PM
    7. Claire avatar

      THANKYOU!! Honestly I'd bloody hug you..

      Claire — May 28, 2009 1:00 AM
    8. test avatar

      this is great, its working for me :)

      test — June 4, 2009 11:01 PM
    9. lusus avatar

      Not only is this a great solution but is accompanied with a great explanation. I have searched and searched on how to resolve this problem. I tried to understand its causes, etc. to no avail. This solution is simple, clean, and most importantly works.

      lusus — September 1, 2009 10:47 AM
    10. Chris avatar

      Thank you! This answered a number of queries/problems in one it! AWESOME!

      Chris — September 14, 2009 11:37 AM
    11. Marko avatar

      thank you so much!! :)

      Marko — September 16, 2009 7:23 AM
    12. Christian avatar

      Nice and elegant workaround. Thanks.

      Christian — September 21, 2009 12:26 PM
    13. mlife avatar

      Cool Tip! Thanks

      mlife — October 2, 2009 4:37 PM
    14. Sean avatar

      Thanks for this, the .databind() call fixed the issue!

      Sean — December 10, 2009 7:37 AM
    15. Chris avatar

      Thanks for the explanantion and resolution.

      Chris — January 22, 2010 11:02 AM
    16. guroo13 avatar

      You Rock!!! Thanks ALOT!

      I was using Databinding Expression and nothing was getting rendered. As soon I put my script in a panel on my usercontrol and then invoked DataBind() on panel at load... It worked like a breeeeeze. I was stuck on it for last two days.

      guroo13 — February 7, 2010 1:29 PM
    17. Asif Siddique avatar

      Excellent post dude.

      Asif Siddique — February 24, 2010 1:06 AM
    18. will avatar

      thanks. it works!

      will — February 24, 2010 10:37 AM
    19. Kumaravelan avatar

      Thanks dude!

      Kumaravelan — March 5, 2010 9:32 PM
    20. Najeeb avatar

      Thank you - I have been facing this issue for two days.

      Najeeb — March 16, 2010 6:17 AM
    21. Gerard Torres avatar

      thank you thank you thank you thank you thank you thank you. man I spent hours trying to figure out this problem and I was at a point where I was trying find ANY answer much less one as elegant as this. I'll tell you what though; re-basing is not working for my css sheet referenced in a link tag in the header so I used your solution there too. worked great!

      Gerard Torres — April 7, 2010 2:18 PM
    22. Eric Huynh avatar

      Very good post! I have been trying to find a fairly elegant implementation of this for the past few days. This helped us out considerably. Awesome job, Thanks!

      Eric Huynh — April 9, 2010 6:24 PM
    23. Yogesh Jindal avatar

      Thanks, that works great.

      Yogesh Jindal — April 19, 2010 11:25 AM
    24. Rama avatar

      Mind blowing! Phenomenal!

      Rama — May 13, 2010 3:47 AM
    25. Daniel Serodio avatar

      What if I can't change the "code behind"? I'm trying to customize a closed product for which I don't have the source code, I can only change the .aspx files

      Daniel Serodio — June 8, 2010 10:39 AM
    26. Kannabiran avatar

      Hi,

      This is awesome stuff... It saved my day.

      Kannabiran — June 17, 2010 1:20 AM
    27. saeid mohammad hashem avatar

      thank you so much. it's worked perfectly.... :*

      saeid mohammad hashem — July 14, 2010 2:50 AM
    28. Chris Miller avatar

      Thank you, that helped me out of a jam.

      Chris Miller — July 14, 2010 3:31 PM
    29. ajnar avatar

      Really well put.

      Thanks

      ajnar — July 31, 2010 7:55 AM
    30. Yavuz Yigit avatar

      Thank you, this is a best solutıon.

      Yavuz Yigit — September 2, 2010 4:29 AM
    31. Matt avatar

      you sir, are amazing. thanks! I'll probably be posting a blog about this and that i found the fix on your site :) thanks again.

      Matt — October 6, 2010 4:53 PM
    32. shideh avatar

      i was facing thisproblem for today , thank you so much it saved my day

      shideh — October 23, 2010 12:32 PM
    33. Gopal avatar

      Very good and simple solution. Excellent Thanks

      Gopal — October 26, 2010 3:13 AM
    34. Kobus avatar

      Excellent solution.. thanks man

      Kobus — November 17, 2010 2:37 AM
    35. Lauga avatar

      Thank you thank you thank you thank you thank you! :-)

      Lauga — January 28, 2011 3:41 AM
    36. Wow, thanks for the great tip!

      Gordon — February 16, 2011 10:09 AM
    37. John avatar

      Great !

      John — February 17, 2011 2:21 AM

    » Leave a Comment