Tuesday, April 23, 2013

Asp.net MVC 4 performance optimization with bundling and minification


Asp.net MVC 4 performance optimization with bundling and minification

Posted By : Shailendra Chauhan, 04 Jan 2013
Updated On : 06 Jan 2013
Version Support : MVC4
MVC4 and .Net Framework 4.5 offer bundling and minification techniques that reduce the number of request to the server and size of requested CSS and JavaScript library, which improve page loading time.
System.Web.Optimization class offers the bundling and minification techniques that is exist with in the Microsoft.Web.Optimization dll. Using this dll you can also use this technique with Asp.Net MVC3 and .Net Framework 4.0. Refer the article Bundling and minification in MVC3 and Asp.Net 4.0 for more help.

What is Bundle?

A bundle is a logical group of files that is loaded with a single HTTP request. You can create style and script bundle for css and javascripts respectively by calling BundleCollection class Add() method with in BundleConfig.cs file.

Creating Style Bundle

  1. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
  2. "~/Content/mystyle.min.css"));

Creating Script Bundle

  1. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
  2. "~/Scripts/jquery-1.7.1.min.js",
  3. "~/Scripts/jquery.validate.min.js",
  4. "~/Scripts/jquery.validate.unobtrusive.min.js"));
Above both the bundles are defined with in BundleConfig class as shown below:
  1. public class BundleConfig
  2. {
  3. public static void RegisterBundles(BundleCollection bundles)
  4. {
  5. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
  6. "~/Content/mystyle.min.css"));
  7. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
  8. "~/Scripts/jquery-1.7.1.min.js",
  9. "~/Scripts/jquery.validate.min.js",
  10. "~/Scripts/jquery.validate.unobtrusive.min.js"));
  11. }
  12. }

Creating Bundle using the "*" Wildcard Character

"*" wildcard character is used to combines the files that are in the same directory and have same prefix or suffix with its name. Suppose you want to add all the scripts files that exist with in "~/Script" directory and have "jquery" as prefix then you can create bundle like below:
  1. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/jquery*.js"));
You can also add all the css that exist with in "~/Content" directory and have ".css" extension(as suffix) like below:
  1. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/*.css"));

Registering Bundle

All bundles are registered with in Application_Start event of Global.asax file of you web application.
  1. protected void Application_Start()
  2. {
  3. BundleConfig.RegisterBundles(BundleTable.Bundles);
  4. // Other Code is removed for clarity
  5. }

Minification

Minification is technique for removing unnecessary characters (like white space, newline, tab) and comments from the JavaScript and CSS files to reduce the size which cause improved load times of a webpage. There are so many tools for minifying the js and css files. JSMin and YUI Compressor are two most popular tools for minifying the js and css files.
You can also add WebEssentials2012.vsix extension to your VS2012 for minifying the js and css files. This is a great extension for VS2012 for playing with js and css.

Minification with VS2012 and WebEssentials 2012 extension

I would like to share how can you make minify version of you css file using WebEssentials extension and VS2012. This minify version will updated automatically if you will make change in original css file.
  

Performance Optimization with Bundling and Minification

I have done a performance test on a MVC4 application with & without bundling and minification. I have noticed the below result.

Without Bundling and Minification

I have the below css and js files on the layout page and run the application in chrome browser and test no of request and loding time using chrome developer tools as shown below.
  1. <link href="~/Content/Site.css" rel="stylesheet"/>
  2. <link href="~/Content/MyStyle.css" rel="stylesheet"/>
  3. <script src="~/Scripts/jquery-1.7.1.js"></script>
  4. <script src="~/Scripts/jquery-ui-1.8.20.js"></script>
  5. <script src="~/Scripts/jquery.validate.js"></script>
  6. <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
In this test, I have seen, There are 7 request, total data size is 3.96KB and loading time is approximate 296ms.

With Bundling and Minification

I have run the above application with Bundling and Minification of css and js files and test no of request and loding time using chrome developer tools as shown below.
  1. @Styles.Render("~/Content/css")
  2. @Scripts.Render("~/bundles/jquery")
In this test, I have seen, There are only 3 request, total data size is 2.67KB and loading time is approximate 80ms. In this way by using bundling and minification you have reduced the total no of request, size and loading time.

Enabling Bundling and Minification in debug mode

Bundling and minification doesn't work in debug mode. So to enable this featues you need to add below line of code with in Application_Start event of Global.asax.
  1. protected void Application_Start()
  2. {
  3. BundleConfig.RegisterBundles(BundleTable.Bundles);
  4. //Enabling Bundling and Minification
  5. BundleTable.EnableOptimizations = true;
  6. // Other Code is removed for clarity
  7. }

Busting Browser's Cache by Bundling

As you know browsers cache resources based on URLs. When a web page requests a resource, the browser first checks its cache to see if there is a resource with the matched URL. If yes, then it simply uses the cached copy instead of fetching a new one from server. Hence whenever you change the content of css and js files will not reflect on the browser. For this you need to force the browser for refreshing/reloading.
But bundles automatically takes care of this problem by adding a hashcode to each bundle as a query parameter to the URL as shown below. Whenever you change the content of css and js files then a new has code will be generated and rendered to the page automatically. In this way, the browser will see a different url and will fetch the new copy of css and js.
What do you think?
I hope you will enjoy the tips while performance optimization of your MVC4 application. I would like to have feedback from my blog readers. Your valuable feedback, question, or comments about this article are always welcome.

Monday, April 22, 2013

多伦多家具店大扫荡

http://post.iask.ca/canadameet/topic/160169

Localization MVC


The right way to use resource files for localization and internationalization in an ASP.NET MVC application

Before I switched to ASP.NET MVC as my server-side web application framework I used to define controls in ASPX pages that referred to locally defined resources in the following way:
1<asp:Button ID="btnReset" runat="server" meta:resourceKey="btnReset" />
Let's assume that the button is defined in a page Default.aspx. The btnReset resource key defines an entry in the file Default.aspx.resx in the App_LocalResources folder. This folder and the Default.aspx file share the same parent directory. If we look at the source of the .resx file we can find the following XML element, that defines the text of the button:
1<data name="btnReset.Text" xml:space="preserve">
2    <value>Reset layout</value>
3</data>
Recently I needed to localize an MVC application and had already started to add App_GlobalResources and App_LocalResources folders to my Visual Studio 2010 solution. Then I remembered a .NET expert writing that this is not the right way to use resources in ASP.NET MVC. To summarize him, resource files in MVC can be added to any directory (or a separate class library). More important, after compilation the files cannot only be referenced in views but also in unit tests (a big advantage). I decided to follow K. Scott Allen's suggestion and assign the namespace pattern "Resources.Controller.View" to .resx file names, for resources dedicated to specific views. In fact, each resource file has two properties that must be set (in the Visual Studio property window for the file) before the entries in the file can be referenced from a view:
  • The Custom Tool property must be set to 'PublicResXFileCodeGenerator' instead of 'ResXCodeFileGenerator'.
  • The Custom Tool Namespace should be set to something meaningfull. What this is, is up to you. Like I said, I use the pattern "Resources.Controller.View". Thus, I define resources for the 'Index' view that is created by the Home controller in a file named Strings.resx that gets the namespace Resources.Home.Index. Also, there is a file Strings.resx with the custom tool namespace Resources.Home.About, for the 'About' view that is created by the same controller.
The Strings.resx files are located in a Resources folder in the root of the MVC web application. The structure of that folder is:
Resources
  |- Account
    |- Logon
      |- Strings.fr.resx
      |- Strings.resx
    |- Register
      |- Strings.fr.resx
      |- Strings.resx
  |- Home
    |- About
      |- Strings.fr.resx
      |- Strings.resx
    |- Index
      |- Strings.fr.resx
      |- Strings.resx
Another thing that may not be immediately clear is how to refer to the resources from a Razor view (.cshtml) file. Here are the contents of the Index.cshtml file that comes with each new MVC project in Visual Studio:
1@{
2    ViewBag.Title = @Resources.Home.Index.Strings.Title;
3}
4 
5<h2>@ViewBag.Message</h2>
6<p>
7    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc"title="ASP.NET MVC Website">http://asp.net/mvc</a>.
8</p>
Note that the string "Home Page" that is normally assigned to ViewBag.Title has been 'localized' and therefore moved to the Strings.resx file in the Resources > Home > Index directory.