Skip to content

Using SquishIt programmatically without the file system

AlexCuse edited this page Dec 19, 2014 · 15 revisions

If your environment does not allow reading/writing to the file system, you may be ready to turn your back on SquishIt. Don't! It is entirely possible to use SquishIt programmatically.

Setting up your Global.asax

The trick is to programmatically define your bundles in a Application_Bundle method of your Global.asax file. You will call this method in Application_Start.

protected void Application_Start() {
    // ... everything else

    // SquishIt
    Application_Bundle();
}

protected void Application_Bundle() {
    //SquishIt
    Bundle.Css()
	.Add("~/Content/Base.css")
	.Add("~/Content/MainStyle.css")
	.AsCached("main", "~/assets/css/main");
}

The key is the AsCached method. The first argument is the name of your bundle (or key) and the next is the server URL SquishIt should use (the {id} is the key name, e.g. main). As you can probably tell, we will need an AssetsController in our project.

Setting up an AssetsController

This is simple. If you are using the regular {id} in MVC for your identifier arguments, simply create a new controller and inherit from SquishItController.

However, if you are either using a custom BaseController or using a different name for the typical {id} field (e.g. {identifier}) you will need to copy the SquishItController code into your own controller. Be sure to specify that the content type is "text/css" for your CSS bundles. An example is below:

// could inherit directly from SquishItController but we use "identifier" as ID parameter in route not "id"
public class AssetsController : BaseController //: SquishItController
{
	public ActionResult Js(string identifier)
	{
            // Set max-age to a year from now
            Response.Cache.SetMaxAge(TimeSpan.FromDays(365));
	    return Content(Bundle.JavaScript().RenderCached(identifier), "text/javascript");
	}

	public ActionResult Css(string identifier)
	{
            // Set max-age to a year from now
            Response.Cache.SetMaxAge(TimeSpan.FromDays(365));
	    return Content(Bundle.Css().RenderCached(identifier), "text/css");
	}
}

Using SquishIt in your views

Almost done. Now you just need to render your scripts to your views. Luckily, it's one line of code!

@Bundle.Css().MvcRenderCachedAssetTag("main")
@Bundle.JavaScript().MvcRenderCachedAssetTag("mainscripts")

You will need to import or set up the appropriate SquishIt namespace to use these in the views. SquishIt.Mvc is not referenced by default if you obtained SquishIt from Nuget. You must add a reference manually, it is stored in /packages/SquishIt-xxx/optional/SquishIt.Mvc.dll.

It may be useful writing a Razor helper to shorten it even more:

// App_Code\Rzr.cshtml

@helper Css(string key) {
  @Bundle.Css().MvcRenderCachedAssetTag(key)
}
@helper Js(string key) {
  @Bundle.JavaScript().MvcRenderCachedAssetTag(key)
}

// In a view...
@Rzr.Css("main")
@Rzr.Js("main")

Setting up a HTTP Handler (for asp.net webforms application)

This is relatively simple, however you want to be careful on how you do your request identification. There may be a better way, but this is what works for me.

My web.config file has the following entry

  <system.webServer>
    <handlers>
      <add path="*.css,*.js" name="BundledResourceHandler" type="BundledResourceHandler" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>
    </handlers>
  </system.webServer>

Assuming that my Bundles work like this

Bundle.Css().AsCached("libs_css", "~/css/libs_#.css");
Bundle.JavaScript().AsCached("libs_js", "~/javascript/libs_#.js");

The actual HTTP Handler looks like this

    public class BundledResourceHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            var path = context.Request.FilePath;
            var extension = VirtualPathUtility.GetExtension(path);
            var filename = VirtualPathUtility.GetFileName(path);
            if (filename != null)
            {
                if (extension == ".css")
                {
                    if (filename.StartsWith("libs_"))
                    {
                        context.Response.ClearContent();
                        context.Response.Write(Bundle.Css().RenderCached("libs_css"));
                        context.Response.End();
                    }
                }
                else if (extension == ".js")
                {
                    if (filename.StartsWith("libs_"))
                    {
                        context.Response.ClearContent();
                        context.Response.Write(Bundle.JavaScript().RenderCached("libs_js"));
                        context.Response.End();
                    }
                }
            }
        }

        public bool IsReusable { get { return false; } }
    }