Sunday 26 June 2016

Setting up Bundling and Minification for ASP.NET Web Pages C# & VB

It can be quite frustrating when you receive complaint from customer regarding the application that you have developed perform very slow. You have tried to tune your application, move some of the non-business processing logic to javascript, added 3rd party javascript libraries to simplify the implementation and it just doesn't load fast enough. End up your application need to load up a lot of javascript files with some of them are quite large in file size.

To solve this, you may want to use bundling and minification techniques which are available on ASP.NET 4.5 onward. Thanks to my mentor Serena Yeoh for introducing this. The bundling is to combine all javascript and css files into 1 file of javascript and 1 file of css. This is to reduce the number of requests to the server to fetch different javscript and css files. Minification is to reduce the size of the javascript and css file. Check out here http://www.asp.net/mvc/overview/performance/bundling-and-minification to know more about bundling and minification.

If you create a web forms or MVC project, by default the bundling has been configured for you. So for those who creates ASP.NET Web Pages project, then this post is for you. So let's get started.

1) Create a Web Application project.

Visual Studio - Add New Project Window

2) Under "Select a template", choose "empty" and click OK button.

Visual Studio - New ASP.NET Project Window

3) NuGet "Microsoft ASP.NET Web Pages" and "Microsoft ASP.NET Web Optimization Framework".

Manage NuGet Packages - Microsoft ASP.NET Web Pages
Microsoft ASP.NET Web Pages

Manage NuGet Packages - Microsoft ASP.NET Web Optimization Framework
Microsoft ASP.NET Web Optimization Framework

4) Place the following configuration in your web configuration file. Change the namespace value "WPBDemo" to your web application project's namespace.

[web.config]
<configSections>
  <sectionGroup name="system.web.webPages.razor"
                type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    <section name="host"
             type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
             requirePermission="false" />
    <section name="pages"
             type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
             requirePermission="false" />
  </sectionGroup>
</configSections>
<system.web.webPages.razor>
  <host factoryType="System.Web.WebPages.Razor.WebRazorHostFactory, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="System.Web.WebPages.WebPage">
    <namespaces>
      <add namespace="System.Web.Optimization" />
      <add namespace="WPBDemo" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

5) Create a folder named "App_Start" in your web application project and create a class file named "BundleConfig.cs".

BundleConfig.cs

6) In your "BundleConfig.cs" file. Create a static method with no return type called "RegisterBundles" that contain 1 parameter with datatype "BundleCollection".

[C#]
public static void RegisterBundles(BundleCollection bundles)
{
   
}

[VB]
Public Shared Sub RegisterBundles(ByVal bundles As BundleCollection)
   
End Sub

7) In the RegisterBundles method, assuming you have AngularJS and Bootstrap added to your web application. Add a new instance of ScriptBundle for javascript files and add a new instance of StyleBundle for css files. You can add as many ScriptBundle or StyleBundle as you want. The ScriptBundle and StyleBundle instance that you defined here will be used in your razor page.

[C#]
bundles.Add(new ScriptBundle("~/bundles/demo").Include(
              "~/Scripts/angular.js",
              "~/Scripts/angular-resource.js",
              "~/Scripts/angular-animate.js",
              "~/Scripts/angular-sanitize.js",
              "~/Scripts/angular-ui/ui-bootstrap-tpls.js"
            ));

bundles.Add(new StyleBundle("~/content/css").Include(
            "~/Content/bootstrap.css",
            "~/Content/ui-bootstrap-csp.css"
          ));

[VB]
bundles.Add(new ScriptBundle("~/bundles/demo").Include(
              "~/Scripts/angular.js",
              "~/Scripts/angular-resource.js",
              "~/Scripts/angular-animate.js",
              "~/Scripts/angular-sanitize.js",
              "~/Scripts/angular-ui/ui-bootstrap-tpls.js"
            ))

bundles.Add(new StyleBundle("~/content/css").Include(
            "~/Content/bootstrap.css",
            "~/Content/ui-bootstrap-csp.css"
          ))

8) To register the files that you have configured to bundle, you can either create a startup class or Global.asax file and use either 1 of them to register the bundle. In the following code snippet, Global.asax is used.

[C#]
protected void Application_Start(object sender, EventArgs e)
{
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

[VB]
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    BundleConfig.RegisterBundles(BundleTable.Bundles)
End Sub

9) For your web page to request for the bundled files. Place the following code into your .cshtml (C#) or .vbhtml (VB) file. The string value passed in are based on what you have defined in "BundleConfig.cs" file.

[Razor]
@Scripts.Render("~/bundles/demo")
@Styles.Render("~/Content/css")

10) For the bundling and minification to take effect, run your application in release mode or execute the following code in "RegisterBundles" method.

[C#]
BundleTable.EnableOptimizations = true;

[VB]
BundleTable.EnableOptimizations = true

When you run your application in debug mode, you will noticed through Internet Explorer's Network tab that on page load, it will attempt to send request for every javascript file needed by this web page. Whereas if you run your application in release mode, only 1 request is send for javascript and 1 request is send for css. Total estimated packet size is 1.72MB in debug mode and 430,78KB in release mode. With fewer requests made to the server and smaller packet size, page loading time improves.

Internet Explorer - Network Tab - Release Mode
Run in release mode.

Internet Explorer - Network Tab - Debug Mode
Run in debug mode.
Note: If and only if you noticed that after you published your project but the javascript or css file did not minified properly, Remove all javascript file that ends with min.js and css files that ends with .min.css from your published folder.

You may refer to the demo application here https://1drv.ms/u/s!Aj2AA7hoIWHmgm17PymRScvyhCAB




No comments:

Post a Comment