Chapter 4

Fine-tuning the ASP.NET MVC 4 Project for Performance

EXERCISES AND EXAMPLES

IN THIS CHAPTER

  • Capturing performance statistics with Fiddler
  • Using MiniProfiler to implement a website and Web Role
  • Utilizing Internet Explorer F12 Developer tools to capture performance data
  • Using Google PageSpeed on your ASP.NET website
  • Reducing JavaScript and CSS files by bundling and minifying
  • Setting up compression and caching
  • Fine-tuning ASP.NET MVC 4 performance

Wrox.com Code Downloads for this Chapter

You can find the wrox.com code downloads for this chapter at www.wrox.com/go/azureaspmvcmigration on the Download Code tab. It is recommended that you download the code and review it so that you have a good understanding of what is about to be discussed. The steps in this chapter cover baseline performance setting techniques, and ASP.NET Web Forms and ASP.NET MVC 4 optimization features.

As discussed in the previous chapter, the performance of your system is critical to its success. If your website runs slow, visitors are very unlikely to return to it. This chapter has examples and tips on how to fine-tune and optimize the ASP.NET, ASP.NET MVC 4 website, and ASP.NET MVC 4 Web Role.

Before you begin implementing any change, it is always a good idea to set a performance baseline for what you are about to change. By doing this, you can see how the change impacts your system. You may be surprised that a change you expected to have a big impact actually had no or even a negative impact. However, without knowing the current status, there is actually no way of telling how the change affected the system . . . unless it is absolutely obvious.


NOTE The following exercises provide step-by-step instructions for optimizing the performance of your ASP.NET MVC 4 project. You can use the projects created in Chapter 2 as a starting point for this chapter’s exercises. If you are not familiar with the concepts behind this chapter, please read through Chapter 3 before continuing.

USING FIDDLER TO CAPTURE PERFORMANCE STATISTICS

To capture some performance statistics, you can use a free tool called Fiddler. Although Fiddler is commonly used to troubleshoot issues happening between the browser and the web server, you can also use it to see how fast a web page can render. For this section, the purpose of these statistics is to set a baseline for you to use when you compare the results of optimizations performed later in this chapter.

To use Fiddler to capture performance statistics for both the ASP.NET website and ASP.NET MVC 4 project, perform the following steps:

1. Download and install the free Fiddler tool at http://www.fiddler2.com.
2. Open Fiddler and confirm the Capture Traffic menu item is checked, as shown in Figure 4-1.
3. Open a web browser and access the web page you wish to measure using Fiddler. For example, http://mvc-4.cloudapp.net/Blogs/BlogLocator/100
4. Highlight the requests in the Web Sessions panel. The top figure in Figure 4-2 shows the ASP.NET website (http://aspnet.thebestcsharpprogrammerintheworld.com/blogs/Using-the-as-keyword-versus-boxing.aspx), and bottom figure shows the ASP.NET MVC 4 (http://mvc-4.cloudapp.net/Blogs/BlogLocator/100).
5. On the right side of the Fiddler console, you see a group of tabs. Select the Statistics tab to see results similar to Figure 4-3. The top figure shows the ASP.NET website and the bottom shows the ASP.NET MVC 4 Web Role.
6. Using the data logged in the Statistics tab, you can get a good view of the size and performance of the page. Also, if you perform a search from any Internet search engine for web page analyzer, you can find some links to other tools that perform similar types of analyses online. Choose one and build a baseline for your system or for this exercise.

For the following exercises, the statistics captured for baseline analysis and the basis for improvement are shown in Table 4-1 (for the ASP.NET Website) and Table 4-2 (for the ASP.NET MVC 4 Web Role).

TABLE 4-1: ASP.NET website Performance Baseline

ATTRIBUTE VALUE
# of HTTP requests (objects) 29–61
Total size (bytes) 205 K–745.9 KB
Total download time (seconds) 3.03–6.89
HTML size (bytes) 36.7–79.2
HTML download time (seconds) .39
CSS size (bytes) 11.4
CSS download (seconds) .46
Image size (bytes) 94.2–104.8
Image download (seconds) 4.3
Script size (bytes) 63.3–547.2
Script download (seconds) 1.74
Total header sizes (bytes) 23.6 KB

TABLE 4-2: ASP.NET MVC 4 Web Role Baseline

ATTRIBUTE VALUE
# of HTTP requests (objects) 14–33
Total size (bytes) 161 KB–376 KB
Total download time (seconds) 3.2–3.7
HTML size (bytes) 5.5–42.8
HTML download time (seconds) 1.67
CSS size (bytes) 1.9 KB
CSS download (seconds) .21
Image size (bytes) 25.9KB–88 KB
Image download (seconds) 1.67
Script size (bytes) 65.9–307.3 KB
Script download (seconds) 1.55
Total header sizes (bytes) 13.2

NOTE As shown in Table 4-1 and 4-2, some of the Values have a range. A number of tools were used to capture and view the performance of the webpage instead of relying solely on a single tool.

The statistics captured for the attributes in Table 4-1 and Table 4-2 are from the following URLs:

IMPLEMENTING MINIPROFILER

Before tuning the website and Web Role, you can implement a tool called MiniProfiler. MiniProfiler is a single .NET assembly that, when configured, displays the timing of specific code segments in an ASP.NET page. For example, you can wrap it around a method or a specific line of code in a method. You can also wrap it around an entire ASP.NET page from start to finish.


NOTE You can find more information about the MiniProfiler at http://miniprofiler.com/.

The following exercises in this section provide the implementation instructions for both the sample ASP.NET website and sample ASP.NET MVC 4 project. The MiniProfiler is imbedded to track the performance of the following features contained in both the ASP.NET website and ASP.NET MVC 4 Web Role samples:

  • Total time to load the homepage
  • Time required to load the RSS XML data feed on the homepage
  • Total time to load the sample blog provided in the example
  • Time taken to load the Rating (ASP.NET website-only)
  • Time taken to load the blog comments
  • Time taken to load each of the dynamic data content on the BlogNavBar

Implementing into ASP.NET Website

You can begin by implementing the MiniProfiler capabilities into the ASP.NET website project.

1. Download the ASP.NET website sample code, and open the CSHARP.ASP.NET website project in Visual Studio 2012.
2. Download the MiniProfiler component from http://miniprofiler.com/ or perform step 3.
3. In Visual Studio select Tools ⇒ Library Package Manager ⇒ Package Manager Console, and the console opens, as shown in Figure 4-4.
4. To install the MiniProfiler, enter the install - package MiniProfiler command, as shown in Figure 4-5.
5. The ASP.NET website does not currently have a Global.asax file, but the configuration of the MiniProfiler is best when one exists; therefore, add one to the project. This is accomplished by right-clicking the Csharp.asp.NET project and then clicking Add ⇒ Add New Item ⇒ Global Application Class. Finally, click the Add button, leaving the name as Global.asax. Figure 4-6 illustrates this in more detail.

Adding the Global Class to the App_Code Directory

You will certainly notice that there is no code-behind when you add the file from the previous section. Historically, a Global.asax file is not needed in an ASP.NET Website project, and therefore they were/are not added by default. Also, Microsoft moved away from a code-behind file in this context in favor of the script-based code you see when the Global.asax file is opened. For this example, you simulate a code-behind for the Global.asax by adding a new class named Global to the App_Code directory.

To do this, follow these steps:

1. Remove all the code from the Global.asax file excluding the following code snippet:
<%@ Application Inherits="Global" Language="C#" %>
2. Right-click the App_Code directory in the Csharp.ASP.NET Website project and select Add ⇒ Class. Then enter Global and click OK, as shown in Figure 4-7.
3. Open the App_CodeGlobal.cs class, and make the changes so it contains what is shown in Listing 4-1.

NOTE Listing 4-1 contains the configurations required by the MiniProfiler. The code listing begins tracing at the beginning of the request until the end. This is what delivers the time taken for rendering the homepage and the example blog. Therefore, no specific-code addition is required for those two files.

LISTING 4-1: The Simulated Global.asax.cs Code-behind Class with MiniProfiler Configurations

using System;
using StackExchange.Profiling;
 
public class Global : System.Web.HttpApplication
{
    protected void Application_BeginRequest()
    {
        MiniProfiler profiler = null;
        profiler = MiniProfiler.Start(ProfileLevel.Verbose);
    }
 
    protected void Application_EndRequest()
    {
        MiniProfiler.Stop(true);
    }
}

Configuring and Loading MiniProfiler

Now that you have the code-behind sorted out, you can begin to configure the MiniProfiler and then load it. This includes determining the time it takes to load the homepage, sample blog, rating, blog comments, and dynamic data.

You can do so by following these steps:

1. In the web.config file located in the root directory of the ASP.NET website, add the code shown in Listing 4-2 just before the closing configuration tag, that is, </configuration>. If the <system.webServer> or <handlers> tags already exist, do not duplicate them — add only what is missing.

LISTING 4-2: MiniProfiler Configuration — web.config

  <system.webServer>
    <handlers>
      <add name="MiniProfiler" path="mini-profiler-resources/*" 
           verb="*" type="System.Web.Routing.UrlRoutingModule"
           resourceType="Unspecified" preCondition="integratedMode" />
    </handlers>
  </system.webServer>
2. Open the TopLevel.master file, and add the following code snippet just before the </head> tag. Do the same to the SecondLevel.master page:
<%= StackExchange.Profiling.MiniProfiler.RenderIncludes() %>
3. Right-click the project, and select Use IIS Express, as shown in Figure 4-8.
4. If the IIS Express menu option is not available, close down the solution, and reopen the website using File ⇒ Open ⇒ Web Site, and select the Csharp.ASP.NET website.
5. Click the Open button, and you receive a prompt asking if you want to use Cassini or IIS Express. Choose IIS Express.
6. Open the Default.aspx.cs file and make the following changes to the Page_Load() method, as shown in Listing 4-3.

LISTING 4-3: RSS XML Load — MiniProfiler

using StackExchange.Profiling;
protected void Page_Load(object sender, EventArgs e)
{
  var mp = MiniProfiler.Current;
  using (mp.Step("RSS XML Load "))
  {
     LoadBlogXML();
  }
}
7. Open the BlogsUsing-the-as-keyword-versus-boxing.aspx file, and then find and modify the code segment that loads the Rating control, as shown in Listing 4-4.

LISTING 4-4: Blog Rating — MiniProfiler

<%@ Import Namespace="StackExchange.Profiling" %>
 
<asp:TableRow><asp:TableCell>
  <% using (MiniProfiler.Current.Step("Blog Rating Load"))
  {%>
      <RATING:Rating runat="server" ID="RatingControl" />
  <% } %>                        
</asp:TableCell></asp:TableRow>
8. Implement the profiler around the loading of the blog comments by adding the code, as shown in Listing 4-5.

LISTING 4-5: Blog Comment — MiniProfiler

<asp:TableRow><asp:TableCell>
  <% using (MiniProfiler.Current.Step("Blog Comments Load"))
  {%>
       <FEEDBACK:fbFORM runat="server" ID="FEEDbackForm" />   
   <% } %>                     
</asp:TableCell></asp:TableRow>
9. The last file to modify in this exercise is the IncludeBlogRightColumn.ascx.cs. In this file four methods are profiled:
  • Total number of Blogs ⇒ DisplayTotalBlogs()
  • Total number of Comments ⇒ DisplayTotalBlogComments()
  • Total number of Fundamentals ⇒ DisplayTotalFundamentalComments()
  • Blog Archive list ⇒ DisplayBlogArchive()
Add the code shown in Listing 4-6.

LISTING 4-6: Total # of Blogs - MiniProfiler

using StackExchange.Profiling;
protected int DisplayTotalBlogs()
{
  var mp = MiniProfiler.Current;
  using (mp.Step("DisplayTotalBlogs"))
  {
    return PostsDAC.PostTotalCount();
  }        
}
10. Add the same code pattern as shown in Listing 4-6 to the remaining three methods referenced in the previous four items presented in the bulleted list.

Running the ASP.NET Website

Now that you have all the pieces together, you can run your site, see how it performs, and migrate everything to the server. To do so, follow these steps:

1. Run the ASP.NET website within Visual Studio 2012 by pressing F5, and you see the MiniProfiler tab, as shown in Figure 4-9.
2. Click the tab and view the results. Be sure to also navigate to the sample blog to view the response times of the dynamic content.
3. Migrate your modifications to the server hosting the ASP.NET website, and document the baseline results, as shown in Table 4-3. You need to migrate the ASP.NET website to the server where you want to realize the performance gain. Steps 1 and 2 are only necessary to confirm that the website runs OK and that the performance isn’t worse than expected.

TABLE 4-3: MiniProfiler ASP.NET Website Baseline

PROFILED FEATURE TIME TAKEN (MS)
Homepage 2945.4
  RSS XML load 8.9
Sample Blog page load 4372.8
  Blog Rating load 18.3
  DisplayTotalBlogs 181.2
  DisplayTotalBlogComments 883.8
  DisplayTotalFundamentals 2639.7
  DisplayBlogArchive 231.6

The following are the modified files that you need to publish so that they can measure the performance on a server and not a PC:

  • BinMiniProfiler
  • Global.asax
  • App_CodeGlobal.cs
  • web.config
  • Default.aspx.cs
  • TopLevel.master
  • SecondLevel.master
  • BlogsUsing-the-as-keyword-versus-boxing.aspx
  • IncludeBlogRightColumn.ascx.cs

Implementing into the ASP.NET MVC 4 Web Role

Now that the MiniProfiler is implemented in the ASP.NET website and the baseline timings are logged, you can implement the same into the ASP.NET MVC 4 Web Role.

Installing MiniProfiler

You need to install MiniProfiler, as shown in the following steps:

1. Downloaded the sample ASP.NET MVC 4 Web Role (Chapter 4 - WindowsAzureMVC.zip).
2. Unzip/extract the solution and open it in Visual Studio 2012.
3. Install the MiniProfiler using the Package Manager Console by selecting Tools ⇒ Library Package Manager ⇒ Package Manager Console and enter in the following command:
Install-package MiniProfiler.MVC3

You should see a result similar to Figure 4-5, shown previously, while performing this command on the sample ASP.NET website.

Implementing the Code to Track Features

When complete, begin to implement the code into the ASP.NET MVC 4 Web Role that configures and tracks timings of the chosen features, shown in the following list:

  • Total time to load the homepage
  • Time required to load the RSS XML data feed on the homepage
  • Total time to load the sample blog provided in the example
  • Time taken to load the blog comments
  • Time taken to load each of the dynamic data content on the BlogNavBar

To do this, follow these steps.

1. Open the _Layout.cshtml file located in the ViewsShared directory of the project.
2. Add the following code shown snippet to the top of the page. Notice that a sample _Layout.cshtml file was added to the project named _MINIPROFILER UPDATED_Layout.cshtml. This file contains some examples of the configuration and components to profile.
@using StackExchange.Profiling;
3. Add the code shown in Listing 4-7 to the same ViewsShared\_Layout.cshtml file.

LISTING 4-7: Adding the RenderIncludes() Method — MiniProfiler

        @MiniProfiler.RenderIncludes()
    </body>
</html>
The RenderIncludes() method is placed at the end of the file just before the closing </body> tag.
4. Run the ASP.NET MVC 4 Web Role by pressing F5, and you see the profiler tab in the upper-left side of the web page, as shown in Figure 4-10.

NOTE The inclusion of the MiniProfiler into ViewsShared\_Layout.cshtml file tracks the time from the beginning of the request to the end for every page in the solution. Therefore, the homepage and sample blog do not need any additional configuration for the request time to be profiled.

5. Open the HomeController.cs located in the Controllers folder, and modify the Index() method, as shown in Listing 4-8.

LISTING 4-8: RSS XML Load — MiniProfiler

using StackExchange.Profiling;
 
public ActionResult Index()
{
  ViewBag.Message = "This site is ... Windows Azure.";
  var mp = MiniProfiler.Current;
  using (mp.Step("RSS XML Load"))
  {
    var blogs = BlogListXML();
    return View(blogs);
  }
}
6. Add the same code pattern to the GetCommentsList(int Id) method found in the ControllersBlogController.cs file, as shown in Listing 4-9.

LISTING 4-9: DisplayTotalBlogComments — MiniProfiler

using StackExchange.Profiling;
public IList<Comments> GetCommentsList(int Id)
{
  var mp = MiniProfiler.Current;
  using (mp.Step("DisplayTotalBlogComments"))
  {
    using (ISession session = MvcApplication.SessionFactory.OpenSession())
    using (ITransaction transaction = session.BeginTransaction())
    {
      Blog blog = session.Get<Blog>(Id);
      IList<Comments> comments = blog.comments.ToList<Comments>();
      return comments;
    }
  }
}
7. Capture the dynamic data presented in the BlogNavBar by opening the ModelsBlogNavBarElements.cs file and wrap the queries in the MiniProfiler code, as shown in Listing 4-10. Listing 4-10 shows only the wrapping of the query that retrieves the total number of blogs.
8. Wrap the other three queries, which return the total number of comments, total number of fundamentals, and the blog archive list.

LISTING 4-10: DisplayTotalBlogs — MiniProfiler

using StackExchange.Profiling;
 
var mp = MiniProfiler.Current;
using (mp.Step("DisplayTotalBlogs "))
{
  using (ISession session = MvcApplication.SessionFactory.OpenSession())
  using (ITransaction transaction = session.BeginTransaction())
  {
    IQuery blogQuery = session.CreateQuery("Select count(*) from Blog");
    elements.blogCount = Convert.ToInt32(blogQuery.UniqueResult());
  }
}

After publishing the code changes to your Windows Azure Web Role, you can execute the request for the homepage and sample blog. Document the baseline timings so that you can compare them to the same timings after the optimizations. Table 4-4 represents the baseline timings logged by the profiler.

TABLE 4-4: MiniProfiler ASP.NET MVC 4 Web Role Baseline

PROFILED FEATURE TIME TAKEN (MS)
Homepage 1351.1
  RSS XML load 4.6
Sample Blog page load 2452.4
  DisplayTotalBlogs 288.6
  DisplayTotalBlogComments 34.9
  DisplayTotalFundamentals 47.7
  DisplayBlogArchive 35.9

Figure 4-11 illustrates an example of the MiniProfiler report after clicking the tab.

CAPTURING PERFORMANCE DATA WITH IE F12 DEVELOPER TOOLS

Another very useful tool for measuring performance and for debugging your website is the F12 Developer tool suite. To access these tools, follow these steps:

1. Open Internet Explorer and press F12.
2. Select the Network tab and then click the Start Capturing button.
3. Access the sample ASP.NET website at http://aspnet.thebestcsharpprogrammerintheworld.com/blogs/Using-the-as-keyword-versus-boxing.aspx. Press the Stop Capturing button. The result is a shown in Figure 4-12.
This is a very useful view that details all the requests made to the website, how large they are, and how long they took. The progress bar in the Timings column represents the request versus the response time. The yellow represents the time it takes for the request to occur, the blue represents the time it takes to get a response, and the gray represents the queue time.
4. Perform the same procedure previously discussed to set the baseline for the ASP.NET MVC 4 Web Role, located at http://mvc-4.cloudapp.net/Blogs/BlogLocator/100; the result is shown in Figure 4-13.

If you perform these actions on one of your own websites or Web Roles, you might consider exporting the data by clicking the Save button. You can save the data as XML or CSV format, and use it later to compare it against a more fine-tuned or optimized ASP.NET project.


NOTE The F12 Developer tool has many other useful features for developers and system administrators to better understand how a website is performing. The suite is also very useful for debugging JavaScript, jQuery, and other client-side website issues. Take a look at the numerous resources on the Internet for more details on this suite of tools.

EMPLOYING GOOGLE PAGESPEED — ASP.NET WEBSITE

Google PageSpeed is a very powerful tool that performs analysis on a user-supplied web address. The result of the analyses is a score of somewhere between 0 and 100 — with 100 being the best. For example, entering the following URL into the tool results in a score of 78 points out of 100: http://aspnet.thebestcsharpprogrammerintheworld.com/blogs/Using-the-as-keyword-versus-boxing.aspx.

In addition, one benefit of this online tool is that it provides numerous suggestions that can help the analyzed website perform more optimal. Also, PageSpeed renders a very valuable set of actions items that prioritize the reasons your site did not achieve the full 100 points, listing those actions having the most positive impact first. The actionable items provided after the analysis of the previously entered web address are provided in Table 4-5:

TABLE 4-5: Google PageSpeed Result

RECOMMENDATION PRIORITY
Leverage Browser Caching 1
Enable Compression 2
Serve Scaled Images 2
Optimize Images 3
Bundle and Minify JavaScript, CSS, and HTML 3

When you click any of the suggestions, you navigate to a page describing the action required to implement the suggestion. The following sections illustrate how to implement the first four suggestions in Table 4-5 to see how it improves the score.


NOTE You can find Google PageSpeed at https://developers.google.com/speed/pagespeed/insights, or do an Internet search for Google PageSpeed to find the correct link.

Leveraging Browser Caching

When you have caching content in the browser, it means that if the same file is requested again in the future, instead of performing an HTTP GET to retrieve the content, the content is loaded from the local cache. Because the ASP.NET sample website is held with a hosting provider, you have no possibility of configuring IIS to set the caching properties. In addition, this ASP.NET website is hosted on IIS 6, and there is no simple way to set the Expires header date for static content. Therefore, the configuration is performed in the web.config file in preparation for migration to IIS 7+. For example, the following configuration, shown in Listing 4-11, sets the expiration date of the static content to a date one year in the future.

LISTING 4-11: Setting the Expires Value in the web.config File

<system.webServer>
  <staticContent>
    <clientCache cacheControlMode="UseExpires"
                 httpExpires="Mon, 03 Mar 2014 08:00:00 GMT" />
  </staticContent>
</system.webServer>

Alternatively, you can add the following code snippet at the top of the ASP.NET page. The snippet caches the page for approximately 30 days.

<%@ OutputCache Duration="25920000" VaryByParam="*" %>

Adding both of the elements just mentioned increases the Google PageSpeed by one point. Migrating the ASP.NET website to an IIS 7+ instance increases the score even more.

Enabling Compression

To enable compression using your web.config file add the following configuration, as shown in Listing 4-12.

LISTING 4-12: Configure Compression in Your web.config File

<system.webServer>
  <httpCompression 
      directory="%SystemDrive%inetpub	empIIS Temporary Compressed Files">
    <scheme name="gzip" dll="%Windir%system32inetsrvgzip.dll" />
    <dynamicTypes>
      <add mimeType="text/*" enabled="true" />
      <add mimeType="message/*" enabled="true" />
      <add mimeType="application/javascript" enabled="true" />
      <add mimeType="*/*" enabled="false" />
    </dynamicTypes>
    <staticTypes>
      <add mimeType="text/*" enabled="true" />
      <add mimeType="message/*" enabled="true" />
      <add mimeType="application/javascript" enabled="true" />
      <add mimeType="*/*" enabled="false" />
    </staticTypes>
  </httpCompression>
  <urlCompression doStaticCompression="true" doDynamicCompression="true" />
</system.webServer>

NOTE Both clientCache and staticCompression are accessible in the web.config only in IIS 7+. If these capabilities need to be implemented on an IIS 6 environment, it must be done with IIS.

After you add this configuration, the content types identified by the mimeType value are compressed. Adding and deploying these compression examples increases the PageSpeed score by 2 points.

Serve Scaled Images

There are two files identified in the report as being scaled incorrectly:

  • IIS8.jpg is 49 KB and 421 × 529.
  • c-sharp.jpg is 4 KB and 134 × 128.

It appears that these two images are larger than necessary, and when they are rendered, HTML or CSS resizes them to a smaller size. It makes sense to reduce the size of the files so that they match the size being rendered.

The IIS8.jpg is referenced in the IncludeBlogRightColumn.ascx file and it does indeed include Width="90" and Height="110" values, which reduce its actual values from width="421" by height="529". You must remove the Width and Height settings from the IncludeBlogRightColumn.ascx and reduce the size of the image using an image editor, such as Microsoft Paint (mspaint.exe).

To reduce the image size, follow these simply steps:

1. Open the image in Paint.
2. Press CTRL+W to open the Resize and Show dialog.
3. Click the Pixels radio button.
4. Deselect the Maintain Aspect Ratio check box.
5. Enter 90 and 110 into the Horizontal and Vertical text boxes, respectively, as illustrated in Figure 4-14.
6. Make the same changes to the c-sharp.jpg and the SecondLevel.master page.

The images are now smaller in size (IIS8.png is now 8 KB and c-sharp.png is now 4 KB) and no longer need to be reduced using HTML width and height attributes.

Optimizing Images

PNG image files are considered static files; however, they usually do not benefit from compression because these file are likely already compressed. Nonetheless, you can take some actions to reduce the size without losing the quality of the image.

The results of the Google PageSpeed analysis identified 16 image files, which may result in an approximate 17 KB reduction in the size of the files. This equates to a reduction of more than 25 percent in their original size. Using tools, such as PNGOUT or GIMP, to reduce the size and convert the images from JPG to PNG would create these gains.


NOTE You can download PNGOUT from http://www.advsys.net/ken/util/pngout.htm and GIMP from http://www.gimp.org/.

One of the images identified in the analysis report is the titlebar.jpg. By converting the image from a JPG to a PNG you may reduce the size by 45 percent. Opening the titlebar.jpg in Paint and performing a Save As ⇒ PNG, results in a 33 percent reduction in the size of the file. Now see if you can get the 45 percent reduction using GIMP:

1. After GIMP is downloaded and installed, open the titlebar.jpg by selecting File ⇒ Open.
2. Navigate to the location where the image is stored. Figure 4-15 illustrates this.
3. Select File ⇒ Export to open the Export Image dialog, as shown in Figure 4-16.
4. Enter titlebar.png in the Name field.
5. In the drop-down at the lower right select PNG Image (*.png).
6. Click the Export button, twice.
7. Leave the default settings in the second window.

When exported, check the size of the image. Instead of Paint’s reduction of 33 percent, GIMP reduced the image size by 66 percent; this is even more than the original estimation.

If you perform the same method with the other JPGs and convert them to PNGs (see Table 4-6), you’ll see that not every export does not result in an image size reduction.

TABLE 4-6: Image File Size Before and After Converting with GIMP

FILENAME ORIGINAL SIZE EXPORTED SIZE
Titlebar.jpg/png 6K B 2 KB
5.jpg/png 3.61 KB 3.49 KB
6.jpg/png 3.93 KB 3.87 KB
7.jpg/png 3.64 KB 3.60 KB
IIS8.jpg/png 7 KB 15 KB
Lessons_t.jpg/png 3 KB 4 KB
Reviews_t.jpg/png 3 KB 4 KB
NHibernate_small.jpg/png 3 KB 7 KB
News_t.jpg/png 2 KB 3 KB
Home_t.jpg/png 2 KB 3 KB
Help_t.jpg/png 2 KB 3 KB
Blogs_t_dark.jpg/png 2 KB 4 KB
Newsletter.jpg/png 2 KB 1 KB
Titlebar_sub_nav.jpg/png 960 B 229 B
Eyebrow.jpg/png 803 B 221 B
C-sharp.jpg/png 2 KB 3 KB

You must modify the references made to an image when you notice a reduction in file size. You can do so by changing the image reference from .jpg to .png in the SecondLevel.master and the Blogs/Using-the-as-keyword-versus-boxing.aspx file.


NOTE To further decrease image size, consider reducing the contrast, brightness, hue, saturation, and lightness so that the range of colors is minimized.


NOTE Check and see what Google Speed says about the ASP.NET MVC 4 Web Role. Navigate to the Google PageSpeed site and enter the following URL: http://mvc-4.cloudapp.net/Blogs/BlogLocator/100.

BUNDLING AND MINIFYING JAVASCRIPT AND CSS

Bundling and minification are new to ASP.NET 4.5 and can improve performance by reducing the number of file downloads required to render a page and reducing the size of JavaScript, CSS, and HTML files. They’re defined as:

  • Bundling: To combine a number of different files into a single file
  • Minification: The removal of white space, comments, and the shortening of variable names

Understanding the Impact of Bundling and Minifying Files

To view the impact of implementing these features, follow these steps:

1. Using the F12 Developer tool, access the sample blog, for example http://aspnet.thebestcsharpprogrammerintheworld.com/blogs/Using-the-as-keyword-versus-boxing.aspx. Doing this can result in something similar to Figure 4-17.
2. There are two GET requests for .js files and for .css files. This is a small website, but there are cases when a website would have 20 or more Cascading Style Sheets and 50 or more JavaScripts. Both file types can be bundled and minified, so the size is reduced and the number of requests to retrieve them is drastically reduced.

Implementing Bundling

To implement bundling into the ASP.NET website, perform the following steps:

1. Install the ASP.NET Web Optimization Framework into your project by opening the Package Manager.
2. Select Tools ⇒ Library Package Manager ⇒ Package Manager Console, and enter the following command:
Install-package Microsoft.AspNet.Web.Optimization
3. Open the App_CodeGlobal.cs file, and add the following code shown in Listing 4-13.

LISTING 4-13: Bundling ASP.NET JavaScript Files

void Application_Start(object sender, EventArgs e)
{
  Bundle JSBundle = new Bundle("~/JSBundle");
  JSBundle.Include("~/syntax/scripts/shCore.js");
  JSBundle.Include("~/syntax/scripts/shBrushCSharp.js");
  BundleTable.Bundles.Add(JSBundle);
}
4. Open the sample blog, BlogsUsing-the-as-keyword-versus-boxing.aspx, and add the following code snippet to the beginning of the file:
<%@ Import Namespace="System.Web.Optimization" %>
5. Comment out the current references to the JavaScript files, as shown in Listing 4-14, and add the new reference to the just-created JavaScript bundle shown in the following snippet:
//<script type="text/javascript"
        //src="<%= BundleTable.Bundles.ResolveBundleUrl("~/JSBundle") %>"></script>

LISTING 4-14: Individual JavaScript File References

<script type="text/javascript" src="../syntax/scripts/shCore.js"></script>
<script type="text/javascript" src="../syntax/scripts/shBrushCSharp.js"></script>
6. Run the ASP.NET website and access the sample blog. Using the F12 Developer Tool Suite, notice the two requests for the JavaScript files are no longer executed. As illustrated in Figure 4-18, there is only a single GET request for the JSBundle bundle.

Implementing Minification

Compare the size and time taken between the bundled and nonbundled results (refer to Figures 4-17 and 4-18. Notice that the size reduced from 19.16 KB to 18.68 KB, and the time improved about 4/10th of a second. But you can get additional improvement after implementing minification.

To implement minification:

1. Open the App_CodeGlobal.cs file, and modify the Application_Start() method so that it resembles Listing 4-15.

LISTING 4-15: Add Minification to the Application_Start() Method

void Application_Start(object sender, EventArgs e)
{
  Bundle JSBundle = new Bundle("~/JSBundle", new JsMinify());
  JSBundle.Include("~/syntax/scripts/shCore.js");
  JSBundle.Include("~/syntax/scripts/shBrushCSharp.js");
  BundleTable.Bundles.Add(JSBundle);
}
Notice that when you create the Bundle, the only addition is the new JsMinify() parameter.
2. Press F5 and run the ASP.NET website.
3. Use the IE F12 Developer Tools to see if there are additional improvements in size and speed. For an introduction to F12 Developer tools, you can find some information at this URL: http://msdn.microsoft.com/en-us/library/ie/gg589512(v=vs.85).aspx. Figure 4-19 provides the result of the test.

NOTE Both the size and the time required to retrieve it decreased. This example is a simple one with only two JavaScript files. You might experience even better gains when you optimize more and/or larger files.

4. Implement bundling and minification into the ASP.NET MVC 4 Web Role. After opening the sample ASP.NET MVC 4 Web Role in Visual Studio 2012, press F5 to run the website.
5. Navigate to the sample blog, accessing the sample blog results in two GET requests for the Cascading Style Sheets, as shown in Figure 4-20.
6. Create a Custom Bundle so that instead of two GET requests, only one is submitted and at the same time apply minification. To achieve this open the Global.asax.cs file and add the code shown in Listing 4-16 at the end of the existing Application_Start() method.

LISTING 4-16: Bundling and Minification of CSS in ASP.NET MVC 4 Web Role

Bundle CSSBundle = new Bundle("~/CSSBundle", new CssMinify());
CSSBundle.Include("~/Content/Site.css");
CSSBundle.Include("~/Content/Syntax/Styles/shCoreFadeToGrey.css");
BundleTable.Bundles.Add(CSSBundle);
7. Open the ViewsBlogsUsing-the-as-keyword-versus-boxing.cshtml and replace the existing <link> reference to the following code snippet:
<link type="text/css" rel="stylesheet"
      href="@BundleTable.Bundles.ResolveBundleUrl("~/CSSBundle")" />
That’s it! The Cascading Style Sheets for this page have been bundled and minified.
8. To check the impact, run the ASP.NET MVC 4 Web Role and check the size and time changes for the CSS files. Figure 4-21 represents the changes.

As you’ll notice, there were some significant improvements for both size and speed in this example. Prior to implementing the bundling and minification the total time for download was 134 ms with a combined size of about 22 KB. After the implementation, the download time is 15 ms with a size of 15 KB. That’s almost a 90 percent increase in performance.

CONFIGURING COMPRESSION AND CACHING

A benefit of utilizing a Windows Azure Web Role compared to a Windows Azure Web Site is making a Remote Desktop Connection to the server. This provides the administrator the ability to directly optimize configurations from the IIS Management console.

Implementing Compression

To create a Remote Desktop Connection and connect to the Windows Azure Web Role, review the exercises in Chapter 8 and then follow these steps to implement compression and caching:

1. When connected, open the IIS manager, and in the Features View, select the Compression icon, as shown in Figure 4-22.
2. By default, both static and dynamic compression are enabled. As a test, access the ASP.NET MVC 4 Web Role and review the size of each file downloaded from the ASP.NET MVC 4 Web Role hosted on Windows Azure. Figure 4-23 illustrates a Fiddler trace of the request.

NOTE Pay special attention to the Bytes Received value and the values present in the RESPONSE BYTES (by Content-Type) table. These change significantly when compression is modified.

3. Return to your Remote Desktop Connection, and deselect the static and dynamic compression check boxes. Then select the Apply link in the Action pane, as shown in Figure 4-24.
4. After compression has been disabled, make another request to the ASP.NET MVC 4 Web Role while tracking it in Fiddler and compare it with the values from step 2. You will notice a significant change in size, as illustrated in Figure 4-25.
5. Check the Statistics tabs for both requests, compressed and uncompressed to view the complete time taken to request and render the web page.

Changing the Output Caching

In this section, you make some changes to the Output Caching capabilities so you can understand what the feature does. For example, output caching can be used to store dynamic content in memory so that the script required to generate each request does not need to be executed for each page. This can yield some significant performance improvements.


NOTE This section requires you to make a Remote Desktop Connection. For full instructions on how to do this, refer to Chapter 8.

1. In Visual Studio 2012, open the ASP.NET MVC 4 Web Role and then open the ViewShared\_Layout.cshtml file.
2. Add the code shown in Listing 4-17 to the bottom of the file, just before the closing </body> tag.

LISTING 4-17: Add a DateTime Stamp to the _Layout.cshtml File

<div>@DateTime.Now</div>
3. Make a Remote Desktop Connection to the ASP.NET MVC 4 Web Role, as discussed in Chapter 8, and open the IIS management console.
4. Navigate to and select the ViewsShared\_Layout.cshtml file, as shown in Figure 4-26.
5. When selected, click the Features View tab on the lower-middle section of the IIS management console. Then double-click the Output Caching icon, as shown in Figure 4-27.
6. Select the Add link on the Action pane. The Add Cache Rule window opens, as shown in Figure 4-28.
7. Enter the configurations as shown in Figure 4-28, and select OK.
8. Republish the ASP.NET MVC 4 Web Role so that the DateTime stamp code modification can be rendered.

NOTE Chapter 6 is where the details are provided for publishing a Windows Azure Web Role. You might want to complete this chapter before continuing with this example.

9. Access the main page of the website, select F5 multiple times, and note the DateTime stamp does not change for 30 seconds, as per the configuration.

The fact that the time stamp does not change for 30 seconds means that the page is being cached and therefore is not downloaded, saving bandwidth and increasing performance. In most cases, you would set the file-cache time interval to a value greater than 30 seconds. The actual value is specific to the application hosted on the web site. It is possible for some files not to change for days or weeks. Therefore they do not need to be downloaded again for a longer period of time. An understanding of an application’s purpose is required for setting the proper value for this setting.

COMPARING ASP.NET MVC 4 PERFORMANCE AFTER TUNING

Recall from Table 4-1 that baseline performance metrics were captured. These metrics measured the speed and size of files required to render requests made to the following:

From the captured baseline metrics, the optimizations implemented included:

  • Leveraging browser caching
  • Enabling compression
  • Serve scaled images
  • Optimizing images
  • CSS and JavaScript minification
  • Bundling of CSS and JavaScript files
  • IIS compression and caching

When you learn how to deploy your ASP.NET website and ASP.NET MVC 4 Web Role to the Windows Azure platform discussed in Chapter 5 and how to execute it in Chapter 6, you can redeploy the code enhancements made in this chapter to test and review the improvements. Even better, after testing, you can go straight into the production environment with the most optimal code.

After you deploy the optimized code, you can capture the statics in the same way you captured them when you created the baseline in this chapter. Table 4-6 and Table 4-7 provide the performance metrics after the recommendations presented in this chapter were implemented. Notice that, in almost every case, there was an improvement in speed and, in many cases, a decrease in size.

TABLE 4-6: ASP.NET Website Optimized Performance

ATTRIBUTE VALUE
# of HTTP requests (objects) 25–58
Total size (bytes) 194 K–623.6 KB
Total download time (seconds) 2.15–4.39
HTML size (bytes) 33.4-62.5
HTML download time (seconds) 0.25
CSS size (bytes) 8.12
CSS download (seconds) 0.24
Image size (bytes) 56.3–89.3
Image download (seconds) 3.4
Script size (bytes) 42.1–385.8
Script download (seconds) 0.97
Total header sizes (bytes) 23.6 KB

TABLE 4-7: ASP.NET MVC 4 Web Role Optimized Performance

ATTRIBUTE VALUE
# of HTTP requests (objects) 11–28
Total size (bytes) 134 KB–332 KB
Total download time (seconds) 2.7–3.1
HTML size (bytes) 4.6–36.3
HTML download time (seconds) 1.44
CSS size (bytes) 1.62 KB
CSS download (seconds) 0.19
Image size (bytes) 26.1 KB–87 KB
Image download (seconds) 1.41
Script size (bytes) 66.4–242.9 KB
Script download (seconds) 1.37
Total header sizes (bytes) 14.5

SUMMARY

In this chapter, you captured a set of baseline performance metrics using tools such as Fiddler, MiniProfiler, and the F12 Developer Tool Suite in Internet Explorer. It’s important that you capture the baseline so that you have something to which you can compare your post-optimization performance.

You also used Google PageSpeed to help identify some inefficiencies in the sample ASP.NET website, some of which were referencing an image. You then modified the width and height attributes to reduce the size instead of just reducing the image size. You also ensured that browser caching was implemented effectively.

In addition, you learned that by minifying and bundling CSS and JavaScript files, you could realize gains in performance in both ASP.NET websites and ASP.NET MVC 4 Web Roles.

After you implemented these optimization examples and redeployed the enhanced source code to the respective Windows Azure environments, you saw positive results. In almost every case, there was an improvement in download speed and a reduction in overall download size.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset