Click here to Skip to main content
15,867,686 members
Articles / Web Development / ASP.NET

Include Stylesheets and Scripts From A WebControl In MVC

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
20 Aug 2009CC (ASA 2.5)3 min read 28.4K   10   7
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?

This article was originally posted at http://somewebguy.wordpress.com?p=392

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 1 Pin
omaliju28-Dec-12 5:01
omaliju28-Dec-12 5:01 
QuestionSource Code? Pin
Steve Barker 33318-Aug-11 2:48
Steve Barker 33318-Aug-11 2:48 
GeneralMVC 2 Pin
_The_phantom_30-Apr-10 3:30
_The_phantom_30-Apr-10 3:30 
GeneralRe: MVC 2 Pin
jgd123457-Sep-10 22:12
jgd123457-Sep-10 22:12 
GeneralRe: MVC 2 Pin
webdev_hb8-Sep-10 4:38
webdev_hb8-Sep-10 4:38 
GeneralThats great But.... Pin
icestatue28-Jul-09 5:07
icestatue28-Jul-09 5:07 
I tried something like this once before and I ran into a problem. Each time you throw this User control into a repeater or some other repetitive control it adds a link or script for each repeated item. Was your solution able to solve this issue? I haven't had much time to investigate if or how the AjaxToolkit solves this problem but, it seems that it is something to be aware of.

nothing

GeneralRe: Thats great But.... Pin
webdev_hb28-Jul-09 5:21
webdev_hb28-Jul-09 5:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.