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. "~/insideSa/bottom_header.jpg")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg").
/// </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. "~/insideSa/site.css")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/site.css").
/// </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. "~/insideSa/jquery.js")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js").
/// </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. "~/insideSa/jquery.js")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js").
/// </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 <script> 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. "~/insideSa/bottom_header.jpg")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg").
/// </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. "~/insideSa/site.css")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/site.css").
/// </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. "~/insideSa/jquery.js")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js").
/// </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. "~/insideSa/jquery.js")
/// into a full url (eg. "http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js").
/// </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 <script> 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." );
}
}
}