Content Injector for ASP.NET MVC

Purpose

Content Injector lets you build smarter Views, Partial Views, and Html Helpers which dictate the scripts and style sheets they need. They can safely inject content into the page in areas already rendered, such as the <head> tag, where style sheets and some scripts should be located. Content Injector will also prevent outputting duplicate tags that load your style sheets and scripts.

Your Views and Helpers also can inject hidden fields, array declarations, <meta> tags, JavaScript templates, and any other content to predefined locations on the page.

It compliments other tools, like Web Optimization Framework, by letting them collect and manage data, while letting Content Injector inject the data into the page.

If you are using Web Optimization Framework, consider using Content Injector extensions for Web Optimization Framework.

It supports the ASP.NET Razor View Engine, and is customizable.

Background

Partial Views and Html Helpers inject content into the page at the location where they are defined. This is fine for adding HTML, but often you want these tools to create something more complex, like a calendar control or filtered textbox, which need JavaScript, both in files and inline, and style sheet classes which do not belong side-by-side with the HTML being injected. They belong in specific locations in the page, often in the master page.

The Razor View Engine for ASP.NET MVC does not make this easy.

  • You often have to create @section groups and hope that the containing page knows to load that section. It's even trickier when working within an Html Helper.
  • The same content can be inserted multiple times, such as two Views which add the same <script> tag.
  • Razor's one-pass rendering engine prevents inserting your content in areas of the page that were already rendered. For example, if your View needs a <link> tag in the <head>, it has to know about that before it does its rendering.

Microsoft's Web Optimization framework enhances the collection of scripts and style sheets, but still suffers from the above problems.

Content Injector extends the Razor View Engine to let your Views and Html Helpers register anything they want injected into the page, and handles duplicates correctly. After Razor finishes preparing the page content, Content Injector will act as a post-processor to locate Injection Points throughout the page and replace them with the content your Views and Html Helpers have registered.

Example

Here is a typical master page (_layout.cshtml) when using the Content Injector:

@{
    Injector.ScriptFile("~/Scripts/jquery-1.5.1.min.js");
    Injector.ScriptFile("~/Scripts/modernizr-1.7.min.js");
    Injector.StyleFile("~/Content/Site.css";
}
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    @Injector.InjectionPoint("MetaTag")
    @Injector.InjectionPoint("StyleFiles")
    @Injector.InjectionPoint("ScriptFiles")
</head>
    
<body>
    @Injector.InjectionPoint("ScriptBlocks", "Upper")
    @RenderBody()
    @Injector.InjectionPoint("ScriptBlocks", "Lower")
</body>
</html>

Understanding this code:

  • The Injector element is property on your page that hosts the methods you use to interact with Content Injector. In this case, the user has added two scripts files URLs and a style sheet URL. If you wanted to ensure a specific order to your scripts, you can pass an order value as an additional parameter:
    Injector.ScriptFile("~/Scripts/jquery-1.5.1.min.js", 10);
    
    Injector.ScriptFile("~/Scripts/modernizr-1.7.min.js", 20);
  • The Injector.InjectionPoint() method marks the location for your content associated with the name given. This call does not output your content. Instead, it just leaves a marker for the Content Injector's post processor to cleanup.
  • There are two Injection Points for “ScriptBlocks”. Each has been given a unique grouping name as the second parameter. Any injection of script blocks must use the same group name to be injected into the page. For script blocks, there are typically blocks before and after the HTML the scripts operate upon. We've given them group names of “Upper” and “Lower” here.

Now suppose your View inserted at @RenderBody() needs to use jquery-validation. Its code should include:

@model Models.MyModel
    
@{
    Injector.ScriptFile("~/Scripts/jquery.validate.min.js", 10);
    Injector.ScriptFile("~/Scripts/jquery.validate.unobtrusive.min.js", 11);
}

Here is the resulting HTML output:

<!DOCTYPE html>
<html>
  <head>
  <title>Create</title>
        
  <link href="/Content/Site.css"type="text/css"rel="stylesheet"/>
          
  <script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
        
</head>
<body>
  The view's content goes here.
</body>
</html>

The comment tags that did not have content have been deleted.

Let's add some script blocks, one assigned to the “ScriptBlocks:Upper” Injection Point and the other to the “ScriptBlocks:Lower” Injection Point.

@model Models.MyModel@{   
   Injector.ScriptFile("~/Scripts/jquery.validate.min.js");
   Injector.ScriptFile("~/Scripts/jquery.validate.unobtrusive.min.js");   
   Injector.ScriptBlock(null, "function test() {alert('hello');}", 0, "Upper");   
   Injector.ScriptBlock(null, "test();", 0, "Lower");
}
Getting started
  • Add the ContentInjector.dll assembly to your ASP.NET MVC web application. Requires MVC 3.0 or higher. (Alternatively, add the source code project and set a reference from your application to it.)
    You can add it either using the NuGet Package Manager in Visual Studio or by going here:
    Retrieve assembly
  • Open the Views\web.config file and locate the <system.web.mvc.razor> section.
    • Replace the value of pageBaseType with “ContentInjector.CIWebViewPage”.
    • Add <add namespace="ContentInjector" /> into the <namespaces> block.
    <pages pageBaseType="ContentInjector.CIWebViewPage">
    
       <namespaces>
    
          <add namespace="System.Web.Mvc" />
    
          <add namespace="System.Web.Mvc.Ajax" />
    
          <add namespace="System.Web.Mvc.Html" />
    
          <add namespace="System.Web.Routing" />
    
          <add namespace="ContentInjector" />
    
       </namespaces>
    
    </pages>
    
  • In Application_Start, add this code:
    ViewEngines.Engines.Clear();
    
    ViewEngines.Engines.Add(new ContentInjector.CIRazorViewEngine());
  • Add the customary Injection Points to the master page, as shown in the Example above.
  • Call methods on the Injector property to add content. Methods include ScriptFile(), StyleFile(), ScriptBlock(), MetaTag(), HiddenField(), ArrayDeclaration(), and Placeholder().
    Examples:
    Injector.ScriptFile("~/Scripts/jquery-1.9.1.js");
    Injector.StyleFile("~/Content/StyleSheet.css");
    Injector.ScriptBlock("somekey", "some javascript", 0, "Lower");
    Injector.HiddenField("codes", "AB903F");
    Injector.MetaTag("description", "about my site");
    Injector.Placeholder("<!-- xyz library used under license -->");
    Injector.ArrayDeclaration("myVar", "my string value", 0, "Lower");
    Injector.ArrayDeclaration("myVar", 100, 0, "Lower");
    Injector.ArrayDeclarationAsCode("MyVar", "null", 0, "Lower");
  • Open the Users Guide.pdf and dig in. It provides details on all described above.
  • Use the forums for support and discussions with the community.
  • Use the issues command to report and review bugs.
  • If you are using Web Optimization Framework, consider adding Content Injector extensions for Web Optimization Framework.

No Comments