Hugoware

The product of a web developer with a little too much caffeine

Include Stylesheets and Scripts From A WebControl In MVC

with 8 comments

As of MVC2 this code may not work anymore – Check here for updated code.

Have you ever created a WebControl in MVC and though “Gee, it sure would be nice if I could add a stylesheet/script to the header of my page.” It’s not as easy as it used to be. Lets just pretend you ran this code right here.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<html>
    <head runat="server">
        <title>Just A Test</title>
    </head>
    <body>
        <% Page.Header.Controls.Add(
            new LiteralControl(
                @"<script src=""/script.js"" type=""text/javascript"" ></script>"
                )); %>
    </body>
</html>

It would compile and run just fine but you wouldn’t see your script! That’s because the page life-cycle has come and gone and you’re in the middle of the page render! We’re too late!

Inline code doesn’t make it easy to communicate with other parts of the page. As far as I can tell, inline code is rendered in the same order that it appears on the page (or at least, parsed), so once you finally get to the end of the page, the code at the start has already been executed.

A Workable Solution

I’ve included some code at the end of this post that simplifies the whole process and for the remaining of this post I explain how it works. In an effort to solve this problem I ended up coming up with two extension methods that are attached to the HtmlHelper.

InsertMarker(id) : Creates a point on the page that will render any content that is added to it. Uses the id provided (either an enum or a string)

AppendToMarker(id, content) : Appends the string content to the matching marker id (either an enum or a string)

These methods allow marker points to be added to the page inline and then content appended to each marker, regardless of where they are used. Let’s look at an example of the code. If this code doesn’t make sense just yet, don’t worry — I’ll explain 🙂

A Simple Example

Lets use this code to add a script to the header of our page — but from within a WebControl.

[Index.aspx (the View)]

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<html>
    <head runat="server">
        <title>Just A Test</title>
        <% this.Html.InsertMarker(Document.Head); %>
    </head>
    <body>
        <% this.Html.RenderPartial("SomeControl"); %>
    </body>
</html>

[SomeControl.ascx (the WebControl)]

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% this.Html.AppendToMarker(
    Document.Head,
    @"<script src=""/script.js"" type=""text/javascript"" ></script>"
    ); %>

As you can see, we can pick the name of the marker that we want to append content and it is added to the page — all from within our WebControl! You can define your own custom markers and append content to really anywhere you want on the page. If the marker isn’t found, then the content is never rendered.

How It Works (The Short Version)

Once we’re in the middle of our render event for our page it makes it quite difficult for us to make many changes to the rest of the document. This is where the HttpContext.Response.Filter stream comes in handy. With this stream we’re able to intercept all of the content before it is really sent out.

Each time we set a marker onto the page we place a bit of text to mark it as a point we need to replace before we push the content out. I had preferred the idea of remembering the position of the output stream, but apparently the output stream is written to all at once which took that out of the picture.

Once we’re done its as simple as using a Regular Expression and replacing all of the markers with the correct content.

MVC-ish – Kinda Sorta…

This may not have been what the guys who designed MVC were thinking of when they created it, but the ability to work with multiple areas of the page was definitely a feature that I felt was missing. How could something like this help you with your projects?

Source Code

ContentMarkerHtmlHelper.cs (Source)

.

Written by hugoware

July 28, 2009 at 1:57 am

8 Responses

Subscribe to comments with RSS.

  1. […] to Vote[Del.icio.us] Include Stylesheets and Scripts From A WebControl In MVC « Yet Another WebDev Blog (7…Tuesday, July 28, 2009 from jungchanInclude Stylesheets and Scripts From A WebControl In MVC « Yet […]

  2. […] Include Stylesheets and Scripts To Your Header With MVC […]

  3. Good job!
    Thanks

    Marty

    November 25, 2009 at 10:00 pm

  4. Just tried it in ASP.NET MVC 2. It doesn’t seem to work anymore. We get a “Filtering is not allowed” HttpException.

    noob

    March 12, 2010 at 3:19 am

    • Ouch – That doesn’t sound good… I wonder why they would block that…

      I’ll check it out and update the blog post – Thanks for the heads up!

      hugoware

      March 12, 2010 at 10:32 am

      • Any idea why this Exception is happening? I’m running into a similar thing.

        womp

        April 6, 2010 at 1:02 pm

      • I’ve actually been working on another solution that might be more helpful than this one. Stay tuned 🙂

        hugoware

        April 6, 2010 at 7:14 pm


Leave a comment