Minification of layout_transofrmation.css

September 19, 2014 Digital Experience

We have had multiple requests for a possible option to minify the generated "on the fly" layout_transformations.css file.

Fulfilling this task requires several steps, which I will describe bellow.

First, it is needed to change the default handler once the Bootstrapper completes the initialization in Global.asax file as follows:

public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            Bootstrapper.Initialized += Bootstrapper_Initialized;
        }
 
        void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs e)
        {
            var routesCollection = System.Web.Routing.RouteTable.Routes;
 
            var path = "Sitefinity/Public/ResponsiveDesign/layout_transformations.css";
                            var route = routesCollection
                                                        .Where(r => r.GetType() == typeof(System.Web.Routing.Route) &&
                                                                    (r as System.Web.Routing.Route).Url == path)
                                                        .FirstOrDefault();
                            if (route != null)
                             {
                                  var index = routesCollection.IndexOf(route);
                                    if (index > -1)
                                     {
                                            var currentRoute = routesCollection[index] as System.Web.Routing.Route;
                                            var routeNew = new ResponsiveDesignTransformationRouteHandlerExtended();
                                            currentRoute.RouteHandler = routeNew;
                                     }  
                             }
        }

By using the above approach we are switching the default ResponsiveDesignTransformationRouteHandler with a custom one:

using System;
using System.Linq;
using System.Web;
using System.Web.Routing;
 
namespace SitefinityWebApp.ExtendResponsiveDesign
{
    /// <summary>
    /// Route handler which returns the css styles for the responsive design transformations.
    /// </summary>
    public class ResponsiveDesignTransformationRouteHandlerExtended : IRouteHandler
    {
        /// <summary>Provides the object that processes the request.</summary>
        /// <returns>An object that processes the request.</returns>
        /// <param name="requestContext">
        /// An object that encapsulates information about the request.
        /// </param>
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new ResponsiveDesignTransformationHttpHandlerExtended();
        }
    }
}

Last, we need to implement the new ResponsiveDesignTransformationHttpHandlerExtended:

using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using Telerik.Sitefinity.Modules.Pages;
using Telerik.Sitefinity.Modules.ResponsiveDesign.Web;
 
namespace SitefinityWebApp.ExtendResponsiveDesign
{
    public class ResponsiveDesignTransformationHttpHandlerExtended : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            var oldHandler = new ResponsiveDesignTransformationHttpHandler();
 
            var stringWriter = new StringWriter();
 
            var mockContext = new HttpContext(
                context.Request,
                new HttpResponse(stringWriter));
             
            oldHandler.ProcessRequest(mockContext);
 
            context.Response.Clear();
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.Cache.SetExpires(DateTime.Now.AddHours(1));
            context.Response.ContentType = "text/css";
            Guid pageDataId = Guid.Empty;
 
            CultureInfo culture = null;
            if (context.Request.QueryString["culture"] != null)
            {
                culture = CultureInfo.GetCultureInfo(context.Request.QueryString["culture"]);
            }
 
            if (context.Request.QueryString["pageDataId"] != null)
            {
                pageDataId = Guid.Parse(context.Request.QueryString["pageDataId"]);
            }
            else if (context.Request.QueryString["pageId"] != null)
            {
                Guid pageNodeId = Guid.Parse(context.Request.QueryString["pageId"]);
                var pageNode = PageManager.GetManager().GetPageNodes().SingleOrDefault(pn => pn.Id == pageNodeId);
                 
                if (pageNode != null)
                    pageDataId = pageNode.GetPageData(culture).Id;
            }
 
 
            var css = stringWriter.ToString();
 
            Microsoft.Ajax.Utilities.Minifier myMinifier = new Microsoft.Ajax.Utilities.Minifier();
            var minifiedCSS = myMinifier.MinifyStyleSheet(css);
 
            context.Response.Write(minifiedCSS);
        }
         
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }
    }
}

 

In HttpHandlerResponsiveDesignTransformationHttpHandlerExtended is needed to mock the HttpContext and pass it as a parameter to default ResponsiveDesignTransformationHttpHandler and by doing this, we let the default handler to generate the non-minified css for us.

Microsoft Ajax Minifier is a simple JavaScript and CSS minification Library, which can be easily installed in a Visual Studio project, trough Package Manager Console. By passing the non-minified css string as a parameter to MinifyStyleSheet(), we get the minified css, which is now ready to be recorded in the HttpContext response:

var css = stringWriter.ToString();
 
            Microsoft.Ajax.Utilities.Minifier myMinifier = new Microsoft.Ajax.Utilities.Minifier();
            var minifiedCSS = myMinifier.MinifyStyleSheet(css);
 
            context.Response.Write(minifiedCSS);

I will be happy to receive any feedback for a possible optimization of the code provided!

Vassil Vassilev