Using Embedded Resources for Client Script Blocks in ASP.NET

0 comments suggest edit

A while ago Patrick Cauldwell highlighted a wonderful technique of using embedded resources for unit testing with external files.

Fully on board with Pat, I’ve applied that technique to client script blocks when building web controls and ASP.NET pages.

How often have you written (or had to deal with) crap like this.

string script = "<script language=\"javascript\">"
  + "function SomeFunction(someParam)" + Environment.NewLine
  + "{" + Environment.NewLine
  + "    alert(’Man, this sucks!’);" + Environment.NewLine
  + "}" + Environment.NewLine
  + "</script>";

A preferred approach is to have your client script code in a separate file. For web controls, I generally have a folder named Resources that contains a folder named Scripts. I’ll add my client script files there as embedded resources. In figure 1 below, you can see that I have two script files in my project.

Embedded Scripts\ Figure 1 Script files.

To make sure these files are compiled as embedded resources, I select the files and set the build action to embedded resource in the Properties window as in figure 2.

Embedded Resource \ Figure 2 Build Action = Embedded Resource.

Now when I need to display these scripts in a page, I can use the following code which makes use of my handy dandy ScriptHelper class.

if(!Page.IsClientScriptBlockRegistered("PairedDropDownHandler"))
{
  string script = ScriptHelper.UnpackScript("PairedDropDown.js");
  Page.RegisterClientScriptBlock("PairedDropDownHandler", script);
}

The contents of my embedded script files do not contain the <script> tags. I leave that responsibility to my ScriptHelper class so that these script files can be used as stand alone script files as well. The code for my script helper class is below.

/// <summary>
/// Utility class for extracting embedded scripts.
/// </summary>
/// <remarks>
/// Uses a naming convention. All scripts should be placed 
/// in the Resources\Scripts folder. The scriptName is just 
/// the filename of the script.
/// </remarks>
public static class ScriptHelper
{
  /// <summary>
  /// Returns the contents of the embedded script as
  /// a stringwrapped with the start / end script tags.
  /// </summary>
  /// <param name="scriptName">FileName of the script.</param>
  /// <returns>Contents of the script.</returns>
  public static string UnpackScript(string scriptName)
  {
    string language = "javascript";
    string extension = Path.GetExtension(scriptName);
  
    if(0 == string.Compare(extension, ".vbs", true
      , CultureInfo.InvariantCulture))
    {
      language = "vbscript";
    }
        
    return UnpackScript(scriptName, language);
  }

  public static string UnpackScript(string scriptName, string scriptLanguage)
  {
    return "<script language=\"Javascript\">"
      + Environment.NewLine
      + UnpackEmbeddedResourceToString("Resources.Scripts." + scriptName)
      + Environment.NewLine
      + "</script>";
  }
 
  // Unpacks the embedded resource to string.
  static string UnpackEmbeddedResourceToString(string resourceName)
  {
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    Stream resourceStream = executingAssembly
      .GetManifestResourceStream(typeof(ScriptHelper), resourceName);
    using(StreamReader reader = new StreamReader(resourceStream, Encoding.ASCII))
    {
      return reader.ReadToEnd();
    }
  }
}

You’ll be seeing this ScriptHelper class again when I highlight some controls you might find useful. If you’re already using ASP.NET 2.0 (aka Whidbey), there’s an even better way to handle client files.

UPDATE: I just realized I was using code from a StringHelper class I wrote. I updated that bit to inline the simple functionality.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

8 responses

  1. Avatar for Steven Campbell
    Steven Campbell May 1st, 2005

    This is great, but I would simplify it even further by creating a method that accepts the Page object as a parameter, so it can be used in one line, like:

    ScriptHelper.IncludeScript("PairedDropDownHandler", "PairedDropDown.js", Page)



    or maybe even just



    ScriptHelper.IncludeScript("PairedDropDown.js", Page)



    (defaulting the name of the script block somehow)

  2. Avatar for Scott
    Scott May 2nd, 2005

    This is great as long as you have a small script and no bandwidth requirements. If you have a large piece of javascript, it's often better to reference it using the "src" attribute of the script tag and place it in the path. That way the client browser will download it once and then cache it. Otherwise you end up sending the same script down every time the page loads.



    Of course I'm talking about script files that are measured in K not chars<grin>. If the scripts is really small, then it's better to embed it in a resource file (even though the resource editor in VS 2003 really sucks). Makes the drag and drop deployment of web controls a reality! I've been working on a way to embed the images into a web control assembly and stream them to the client at runtime. I haven't come up with a satisfactory solution yet.

  3. Avatar for haacked
    haacked May 2nd, 2005

    VS.NET 2005 handles that with WebResource.axd I believe. I am planning to tackle that issue as well, though it's lower priority.



    In the meantime, you should take a look at Fritz Onion's dynamic image control.

    http://pluralsight.com/blogs/fritz/archive/2005/02/11/5789.aspx

  4. Avatar for Ramesh
    Ramesh June 28th, 2006

    This is great. But i would like to hide my script from client. but your script helper shows the script in the client.
    If any other way is there please post it.

  5. Avatar for Michael Freidgeim
    Michael Freidgeim August 3rd, 2006

    Your UnpackScript(string scriptName, string scriptLanguage) doesn't use scriptLanguage,but hardcoded it to Javascript

  6. Avatar for james nnannah
    james nnannah February 15th, 2008

    For reasons I cannot fathom, I cannot access the 'build action' property for files or resources included in my project. I am using vs2005 (asp.net 2.0).

  7. Avatar for Samir Nigam
    Samir Nigam March 14th, 2008

    Is it possible to modify content of a embadded resource file?

  8. Avatar for q
    q December 15th, 2009

    qqq