Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Include Stylesheets and Scripts From A WebControl In MVC

0.00/5 (No votes)
20 Aug 2009 1  
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. This post goes over some code that can help you bridge that gap.

Have you ever created a WebControl in MVC and thought “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. Let's just pretend you ran this code right here.

ASP.NET
<%@ 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 top 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)]

ASP.NET
<%@ 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)]

ASP.NET
<%@ 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, it's 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?

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here