MVC Static Content DNS Helper

on Thursday, April 30, 2009

A website I was working on needed a way to include references to static content (images/css/js) which could dynamically point to the correct server for the build environment (dev,test,prod). This was accomplished by creating extension methods for the HtmlHelper.

I recently wrote about using a static content website on a previous post.

We already had an enumeration setup to describe the environment (listed below the post). We just needed a way to parse string values and add the dns name. To do this, we made a class for ASP.NET 2.0 websites and for ASP.NET MVC websites. It also needed to add the “.min.js” extension for production javascript.

ASP.NET 2.0:

using System.Web;
using Ucsb.Sa.Registrar.Util;

namespace Ucsb.Sa.Enterprise.Utility.Web
{
/// <summary>
/// Static content extension methods for <see cref="HtmlHelper" />. This file requires that the web
/// application contains a static AppSettings file with property BuildEnvironment.
/// </summary>
public static class StaticContentExtensions
{

#region variables

private const string BaseImageUrlFormat = "{0}://static.{1}sa.ucsb.edu/{2}";
private const string BasePlaceholder = "~";
private const string Image = "images";
private const string Css = "css";
private const string Js = "js";
private const string JQuery = "js/jquery";

#endregion

#region properties

/// <summary>
/// Gets and Sets the <see cref="BuildEnvironmentType" /> for the application. This
/// should be set before the first call to these extension methods.
/// </summary>
public static BuildEnvironmentType BuildEnvironment { get; set; }

/// <summary>
/// http or https
/// </summary>
public static string Scheme
{
get { return HttpContext.Current.Request.Url.Scheme; }
}

#endregion

#region public methods

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/bottom_header.jpg&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetImageUrl( string partialUrl )
{
return GetUrl( partialUrl, Image );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/site.css&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/site.css&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetCssUrl( string partialUrl )
{
return GetUrl( partialUrl, Css );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJsUrl( string partialUrl )
{
var url = GetUrl( partialUrl, Js );
return RewriteForMinJs( url );

}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJQueryUrl( string partialUrl )
{
var url = GetUrl( partialUrl, JQuery );
return RewriteForMinJs( url );
}

/// <summary>
/// Creates the javascript code to load javascript libraries from google.
/// This will ensure that the uncompressed version of the code is loaded on the developer
/// systems.
/// </summary>
/// <param name="package">The name of the javascript library to load.</param>
/// <param name="version">The version number to retrieve.</param>
/// <returns>The string to be injected into a &lt;script&gt; section.</returns>
public static string GetGoogleLoad( string package, string version )
{
const string format = "google.load('{0}', '{1}'{2}";
const string compressed = ");";
const string uncompressed = ", {uncompressed:true});";

return string.Format(
format,
package,
version,
BuildEnvironment == BuildEnvironmentType.Local ? uncompressed : compressed
);
}

#endregion

#region private methods

private static string GetUrl( string partialUrl, string subDirectory )
{
var baseUrl = string.Format( BaseImageUrlFormat, Scheme, GetEnvironmentString(), subDirectory );
return partialUrl.Replace( BasePlaceholder, baseUrl );
}

private static string GetEnvironmentString()
{
var env = string.Empty; // default value for pilot and production

switch( BuildEnvironment )
{
case BuildEnvironmentType.Local:
case BuildEnvironmentType.Development:
case BuildEnvironmentType.Integration:
env = "dev.";
break;

case BuildEnvironmentType.Test:
env = "test.";
break;
}

return env;
}

private static string RewriteForMinJs( string url )
{
if( BuildEnvironment != BuildEnvironmentType.Production ) return url;
if( string.IsNullOrEmpty( url ) ) return url;

var len = url.Length;
if( len < 3 ) return url;

const string ext = ".js";
if( url.Substring( len - 3 ) != ext ) return url;

const string minExt = ".min.js";
if( url.Substring( len - 7 ) == minExt ) return url;

const string format = "{0}.min.js";
return string.Format( format, url.Substring( 0, len - 3 ) );
}

#endregion

}
}


And the corresponding ASP.NET MVC wrapper:



using System.Web.Mvc;
using Ucsb.Sa.Registrar.Util;

namespace Ucsb.Sa.Enterprise.Utility.Web.Mvc
{
/// <summary>
/// Static content extension methods for <see cref="HtmlHelper" />. This file requires that the web
/// application contains a static AppSettings file with property BuildEnvironment.
/// </summary>
public static class HtmlHelperStaticContentExtensions
{

#region properties

/// <summary>
/// Gets and Sets the <see cref="BuildEnvironmentType" /> for the application. This
/// should be set before the first call to these extension methods.
/// </summary>
public static BuildEnvironmentType BuildEnvironment
{
get { return StaticContentExtensions.BuildEnvironment; }
set { StaticContentExtensions.BuildEnvironment = value; }
}

#endregion

#region public methods

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/bottom_header.jpg&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetImageUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetImageUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/site.css&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/site.css&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetCssUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetCssUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJsUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetJsUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJQueryUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetJQueryUrl( partialUrl );
}

/// <summary>
/// Creates the javascript code to load javascript libraries from google.
/// This will ensure that the uncompressed version of the code is loaded on the developer
/// systems.
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="package">The name of the javascript library to load.</param>
/// <param name="version">The version number to retrieve.</param>
/// <returns>The string to be injected into a &lt;script&gt; section.</returns>
public static string GetGoogleLoad( this HtmlHelper html, string package, string version )
{
return StaticContentExtensions.GetGoogleLoad( package, version );
}

#endregion

}
}


Then we used the static classes in a PartialView for rendering:

<%@ Import Namespace="Ucsb.Sa.Enterprise.Utility.Web.Mvc"%>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<link href="<%= Html.GetCssUrl( "~/reset.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/ie.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/screen.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/print.css" ) %>" rel="stylesheet" type="text/css" media="print" />
<link href="<%= Html.GetJQueryUrl( "~/1_3_2/themes/ucsb/ui.base.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/1_3_2/themes/ucsb/jquery-ui-1.7.1.custom.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/dataTables-1_4/css/datatables.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/mbMenu-2_2/css/menu.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/InsideSa/InsideSaLayout-0.0.0.1.css" ) %>" rel="Stylesheet" type="text/css" media="screen" />


Which generated html that looked like this:

<link href="http://static.dev.sa.ucsb.edu/css/reset.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/ie.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/screen.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/print.css" rel="stylesheet" type="text/css" media="print" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/1_3_2/themes/ucsb/ui.base.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/1_3_2/themes/ucsb/jquery-ui-1.7.1.custom.css" rel="stylesheet" type="text/css" media="screen" />

<link href="http://static.dev.sa.ucsb.edu/js/jquery/dataTables-1_4/css/datatables.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/mbMenu-2_2/css/menu.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/insideSa/InsideSaLayout-0.0.0.1.css" rel="Stylesheet" type="text/css" media="screen" />


Here is the code for the environment variables:

namespace Ucsb.Sa.Registrar.Util
{
/// <summary>
/// Enumeration for each build environment. eg. Development, Test, etc.
/// </summary>
public enum BuildEnvironmentType
{
/// <summary>
/// local, localhost
/// </summary>
Local,

/// <summary>
/// dev, development
/// </summary>
Development,

/// <summary>
/// int, integration
/// </summary>
Integration,

/// <summary>
/// test, qa, quality assurance
/// </summary>
Test,

/// <summary>
/// pilot
/// </summary>
Pilot,

/// <summary>
/// prod, production
/// </summary>
Production
}
}


using System;

namespace Ucsb.Sa.Registrar.Util
{
/// <summary>
/// Attempts to parse string values to BuildEnvironmentType Enumerations.
/// </summary>
public static class BuildEnvironmentTypeParser
{

/// <summary>
/// <para>
/// Parses a string value into the corresponding environment type. Some partial and exact matches can be parsed.
/// </para>
/// <para>ie. Development, dev, prod, test, Production, etc.</para>
/// </summary>
/// <param name="environmentName">string to parse</param>
/// <returns>BuildEnvironmentType from parsed string.</returns>
/// <exception cref="ArgumentException">If the argument is unknown.</exception>
public static BuildEnvironmentType Parse( string environmentName ) {
if( string.IsNullOrEmpty( environmentName ) )
throw new ArgumentException( "Argument environmentName was null or empty." );

switch( environmentName.ToLower().Trim() ) {
case "local": case "localhost":
return BuildEnvironmentType.Local;

case "dev": case "development":
return BuildEnvironmentType.Development;

case "int": case "integration":
return BuildEnvironmentType.Integration;

case "qa": case "quality assurance": case "test":
return BuildEnvironmentType.Test;

case "pilot":
return BuildEnvironmentType.Pilot;

case "prod": case "production":
return BuildEnvironmentType.Production;
}

throw new ArgumentException( "Argument environment name, " + environmentName + ", is of an unknown type." );
}

}
}

0 comments:

Post a Comment


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.