— Tech+Life+Music

Using Razor in Javascript and CSS files

A sample project for this discussion is available over on my Github.

There are countless use cases where I found myself needing to use Razor syntax (in ASP.NET MVC 3+) inside Javascript, CSS and other asset files. While there are many different ways to get Razor output into external JS files (for example, getting a Url.Action() call into a JS file’s jQuery.ajax() call), I find that most feel like beating around the bush. After all, views in MVC don’t always have to be HTML files, at least in the traditional spirit of MVC.

So why not create a Javascript view?

If you think about it, there’s nothing really stopping you from creating a controller, adding in a view, then writing up the view in Javascript syntax (save for the less-than-tasty syntax highlighting and Intellisense in Visual Studio, since it kind of expects that views are HTML files).

The key thing is to modify the Content-Type of the response to the appropriate value, based on what you’re returning. So Javascript files will be text/javascript, CSS files will be text/css. It’s the same basic idea with, for example, returning image data through the wire.

For example, this controller action:

public class AssetController : Controller {
    public ActionResult Styles () {
        Response.ContentType = "text/css";
        var model = Context.GetEntity();
        return View(model);

… can have the following view:

@model Entity;
#entity {
    color : @Model.Color;
    background : url(@Model.BackgroundImage.Url);

… and can be wired into your markup just like any other stylesheet:

<link rel="stylesheet" href="@Url.Action("Styles","Asset")" />

Taking all that a bit further, we can write up an Attribute to easily maintain the corresponding Content-Type to each action:

public class ContentType : FilterAttribute, IActionFilter 
    private string contentType;
    public ContentType (string ct) {
        this.contentType = ct;
    public void OnActionExecuted(ActionExecutedContext context) { /* nada */ }
    public void OnActionExecuting(ActionExecutingContext context) {
        context.HttpContext.Response.ContentType = this.contextType;

… and just mark our actions with it:

public ActionResult Styles() {
    // ...
    return View();

All that notwithstanding though, you’ll still have to deal with two problems when you do this:

  1. Visual Studio assumes that all views are HTML. You don’t get accurate color highlighting and Intellisense in your asset views. I don’t know about you, but the countless ways that VS pushes back when I do this kind of irks me off.
  2. You don’t get bundling (in ASP.NET MVC 4), and unless you wire it up somehow with WebGrease, you don’t get minification either. Caching is possible, but the whole point of dynamic assets are just that: they’re dynamic. You still can cache via normal ASP.NET MVC methods if, for example, you can manage to scope your use cases into unique URLs (via query strings probably), or you could opt to write your own caching mechanism for this.

If you want to try this out, I’ve prepared a very simple VS 2012 MVC 4 project ready to go over on my Github. Feel free to clone, fork, and/or contribute!

With all that said and done though, I believe that this is the way to correctly use views in an MVC framework, and that Visual Studio should perhaps allows for better leniency for use cases such as this. I’d love to hear your ideas on the topic though.

2 comments thrown in. Share your two cents.
  1. ekkis says: December 3, 20139:49 am

    your post reminds me of a similar thought I’ve had that a view could also be an Excel spreadsheet

  2. Richard Neil Ilagan says: December 3, 201310:01 am

    … and your train of thought would be correct.

    A view in an MV* paradigm is any visual representation of your data (of which your model is). Most of the time, that’d be an HTML page (so much that people throw them around as synonyms of each other), but they don’t need to be.

    Views can be PDF files, an XML dump, or an Excel spreadsheet, whatever.

Submit comment