2

I can't figure out how to enable a custom route for static files.

I'd like to setup my asp.net mvc application to use synthetic URLs for versioned assets. This allows me to set expires to max for my static assets, and to have the version be incremented whenever I do a build.

I'd like to put that version into the path of my static assets when composing my cshtml templates. Lastly, I need to setup the routing to ignore the version component of the URL and just serve the static asset.

For example: /js/1.2.3.4/libs/require.js -> /js/libs/require.js

I've got the first two pieces working, but I can't figure out how to have part of a URL ignored for static files.

Layout.cshtml

...
<script data-main="/js/@(((myApplication)(HttpContext.Current.ApplicationInstance)).Version)/config"
    src="/js/@(((myApplication)(HttpContext.Current.ApplicationInstance)).Version)/libs/require.js"></script>
...

myApplication.cs

public class myApplication : HttpApplication {

...

    public string Version { 
        get {
            var baseVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
#if DEBUG
            var span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime());
            baseVersion += "_" + span.TotalMilliseconds;
#endif
            return baseVersion;
        }
    }
}

Edit:

I managed to make a workable solution (courtesy of sheikhomar) using an OnBeginRequest handler at the application to rewrite URL when it matched a regex, but that seems excessive to do that on every request:

private readonly Regex jsPattern = new Regex("^/js/[0-9._]*/(.*)$", RegexOptions.IgnoreCase);

protected void OnBeginRequest(Object sender, EventArgs e) {
    var match = jsPattern.Match(Request.Url.AbsolutePath);
    if (match.Success) {
        var fileName = match.Groups[1].Value;
        Context.RewritePath(string.Format("/js/{0}", fileName));
    }
}
Community
  • 1
  • 1
Ken Perkins
  • 157
  • 7

1 Answers1

3

I would suggest just letting MVC handle the route. Doing URL rewriting outside of the normal MVC route handling is something I would advise against unless you have a really good reason for it. The point of ASP.NET MVC is to eliminate the need for doing these kinds of low-level actions.

Anyway, in MVC, map your route similar to this:

routes.MapRoute("staticJs", "js/{version}/{*fileName}", new { controller = "Static", action = "Js" });

and then in StaticController

public ActionResult Js(string version, string fileName) {
  var basePath = @"c:\path\to\js";
  var realPath = Path.Combine(basePath, fileName);
  return File(realPath, "application/javascript");
}

which will just stream the file back to the client (assuming that c:\path\to\js is the path to the javascript file on disk).

You can consult this answer for more info on FileResults.

Community
  • 1
  • 1
tmont
  • 2,562
  • 20
  • 15