Search This Blog

Loading...

2012-03-18

Render external jQuery Template files with ASP.NET MVC 4

While developing more complex web applications using template engines (maybe together with Backbone.js, Knockout.js, etc.), we come to obvious idea to store template files separately.
Straightforward solution is to load a file with ajax request like:
$.get("templates/Contact.htm", function(template) {
  $("body").append(template);
});
Contact.htm:

There are several great posts about such an issue by Dave Ward, Ryan Niemeye. But I have a little bit modified solution...
New ASP.NET MVC 4 has delivered lots of content, and Bundling feature is a good option to work with scattered files.
Bundling represents a list of JavaScript or cascading style sheet (CSS) files that ASP.NET dynamically combines into a single virtual file that a browser can retrieve by using a single HTTP request.  It is a part of System.Web.Optimization namespace and can be downloaded as a Nuget package.
Bundling basically can combine any files and not js or css ones, so let's try to combine template "htm" files. To do that we simply need to register new Dynamic Folder Bundle on Application Start of Global.asax:
var templateBundle = new DynamicFolderBundle("htm", "*.htm", true);
var context = new BundleContext(new HttpContextWrapper(Context), new BundleCollection(), "~/Templates/htm");
templateBundle.EnumerateFiles(context);
BundleTable.Bundles.Add(templateBundle);
And that's it! With this code
BundleTable.Bundles.ResolveBundleUrl("~/Templates/htm)
we have a url to combined template file, so we can use it inside Razor view like:
$.get(@BundleTable.Bundles.ResolveBundleUrl("~/Templates/htm"), function(templates) {
  $("body").append(templates);
});
A little bit more sophisticated solution is to write html extension for Razor view to get and render template files:
public static class HtmlHelperExtension
{
  public static IHtmlString RenderTemplates(this HtmlHelper htmlHelper, string src)
  {
    var context = htmlHelper.ViewContext.HttpContext;
    if (string.IsNullOrEmpty(src) || context == null || context.Request.Url == null)
    {
      return null;
    }

    var templateUrl = BundleTable.Bundles.ResolveBundleUrl(src);
    var absoluteUrl = new Uri(context.Request.Url, templateUrl);
    var request = WebRequest.Create(absoluteUrl);
    var response = request.GetResponse();
    var stream = response.GetResponseStream();
    if (stream == null)
    {
      return null;
    }

    var data = new StringBuilder();
    using (var sr = new StreamReader(stream))
    {
      string line;
      while ((line = sr.ReadLine()) != null)
      {
        data.AppendLine(line);
      }
    }

    return htmlHelper.Raw(data);
  }
}
Usage:
@Html.RenderTemplates("~/Templates/htm")
As you can see Bundling helps to keep external templates while getting a good design-time experience.

No comments:

Post a Comment