12 tips to increase the performance of your ASP.NET application drastically – Part 1

DevToolsGuy / Friday, August 7, 2015
This is a guest post by Brij Bhushan Mishra, a Microsoft MVP-ASP.NET/IIS ,  C# Corner MVP, CodeProject Insider, Former CodeProject MVP, CodeProject Mentor,  and Platinum Member at CodeProject . He has around 6 years of experience as a Sr. Developer/Architect and a passion for computers since childhood.
 
Building web application and hosting it on a web server is insanely easy with ASP.NET and IIS. But there are lots of opportunities and hidden configurations which can be tweaked that can make it a high-performance web application. In this series post, we are going to discuss some of the most unused or ignored tricks which can be easily applied to any web application.

1-      Kernel mode cache - It is one of the primary tools widely used for writing making web application faster. But most of the times, we don’t use it optimally and just leave some major benefits.  As each asp.net request goes through various stages, we can implement caching at various levels as below

 

We can see that request is first received by HTTP.sys so if it is cached at the kernel level, then we can save most of the time spent on the server as HTTP.sys is an HTTP listener which sits in OS kernel and listens to the request directly from TCP layer. We can save all the time spent IIS/ASP.NET pipeline, page lifecycle, our custom code, the time taken in DB etc. Let’s see how we can implement it.

a)      Go to IIS and select the website.

b)      Click on Output Cache icon on right under IIS section

c)       In the right panel, under Actions click on Add. The following dialog will open:

 

 

Here in the red encircled area, we need to define that the file extensions which we want to cache at the kernel. Second encircled area, we need to select the checkbox. Third encircled area show that there are three options is provided to invalidate the cache. Based on our requirement we can configure it.
Note – there are some limitations over caching in kernel level. As all the features of IIS are implemented at User level so we will not able leverage any of those. Refer this MSDN article for a complete list where kernel caching cannot be implemented.

 

2-      Pipeline mode (Available on IIS 7+) – At application pool level, there are two pipeline modes available: classic and integrated. Classic is available to support the applications that were migrated from IIS6. So first let’s understand these modes. IIS provides many features which are implemented as modules in IIS and in a similar way many features are implemented as an HTTP Module which is part of ASP.NET Pipeline. In case of classic mode, each request goes through first IIS pipeline and then ASP.NET pipeline before getting served. There are many features which are part of both the pipelines like Authentication etc. In case of Integrated mode, these two pipelines are merged into one and all the module (IIS and ASP.NET) are invoked from the single event as they come along which reduces the redundancy and very helpful in the performance of an application.

To set/update the pipeline mode, select the desired application pool and right click properties

 

Here as encircled in the above pic, we can set the pipeline mode.
Note – Don’t go for blindly changing it, if your application migrated from IIS6 then there could be some dependency on it. After changing thoroughly test it before moving ahead.
3- Remove unused Modules – Each request has gone through ASP.NET Pipeline which contains many HTTP modules and at the end one HTTP handler, which serves the request as below
We can see here the request goes through each module, processed by the handler then again come through again via the same modules. Let’s see how many modules are by default enabled in an ASP.NET Application. I have added the below code to get all the modules
HttpApplication httpApps = HttpContext.ApplicationInstance;
 
//Get list of active modules
HttpModuleCollection httpModuleCollections = httpApps.Modules;
ViewBag.ModulesCount = httpModuleCollections.Count;
 
And this collection can be bound to any control and it displays as
It is showing eighteen modules which some of them we may not be using but each request gets has to though these all modules. So we can remove these modules from the pipeline. To remove a module, we just require adding the configuration in web.config as
  <system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
      <remove name="DefaultAuthentication" />
      <remove name="OutputCache" />
      <remove name="AnonymousIdentification" />
      <remove name="RoleManager" />
    modules>
  system.webServer>
Here we list down the modules that we want to remove with remove tag. Now as we added here remove five modules, next time when we will check the active modules, it will be thirteen.
Note – For this demo, I have used VS 2013, you may get a different number when using another version but the key point is that we should remove all the modules which are not required.
 
4 -  runAllManagedModulesForAllRequests - It is another configuration, one must have seen in web.config or applicationHost.config where it is set globally for all the application on that IIS as
<modules runAllManagedModulesForAllRequests="true">
It means all the modules would be running for all the request coming to the application but we normally don’t require that because it should run only ASP.NET files, not other files like CSS, js, jpg, HTML etc. It means even the request of these resources going through the pipeline which is unnecessary for these files and it just adds extra overhead. But we cannot make simply false at application level. So there could be two ways -

a)      Create a different application just for serving these static resources and set this setting as false in web.config.

b)      Or in the same application, put all the static resources in a folder and add a web.config file specific to that folder and make it false.

 

5         Do not write anything in the folder c:\inetpub\wwwroot. - There is a file watcher looks into the folder and if there are any changes in this folder, it restarts the corresponding application pool. This is a feature available in IIS, if there is any change in web.config or any file, it restarts the application pool so that your modified application serves the request. Now say you write the application log in some text file inside the application folder which makes a couple of entries in each request, the application pool would be restarting that many times which would be hazardous for your application. So instead, don’t write or change anything in this folder until it is not part of application binaries.

 

6         Remove extra View Engines – a) As we know View Engines is a part of MVC request life cycle and has a responsibility to find the view and process it. It allows us to add our own custom view engines as well. Let’s create a default MVC application and try to return a view which does not exist in the solution. Now when we run this application this shows the following error.

 
It shows that it is looking for the razor and aspx files to all the possible locations. But as we know that we are using razor view engine so it should not waste time in looking other aspx files because we already know that it is not going to be part of the solution. So we should remove all the extra View Engines.  We need to add following code in the Application_Start method which is available in Global.asax.
            // Removing all the view engines
            ViewEngines.Engines.Clear();
 
            //Add Razor Engine (which we are using)
     ViewEngines.Engines.Add(new RazorViewEngine());
Now let’s run it again
                 Now it is looking for only razor files

b)      If we carefully see the above screenshot then we see that it is looking for c# and vb files and say in our solutions we have never used vb, so again there is no use of looking for vbhtml files. To fix this we need to write our own custom ViewEngine. So let’s write our Custom RazorViewEngine as

    public class MyCustomViewEngine : RazorViewEngine
    {
        public MyCustomViewEngine()
        {
            base.AreaViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml"};
            base.AreaMasterLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml" };
            base.AreaPartialViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml","~/Areas/{2}/Views/Shared/{0}.cshtml"};
            base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
            base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
            base.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
            base.FileExtensions = new string[] { "cshtml" };
        }
    }
Here I have inherited it from RazorViewEngine and if we see the constructor in the then we find that there we have defined all the possible locations where a file can exist which includes possible file extensions as well. Now let’s use this View Engine in Global.asax.
And run the application.
Now it looks for csharp razor files which makes sense and performance friendly.
Conclusion – In this post, we have discussed following six tips which can be easily applied to any ASP.NET application.

1-      Kernel mode Cache

2-      Pipeline mode

3-      Remove unused modules

4-      runAllManagedModulesForAllRequests

5-      Don’t write in wwwroot

6-      Remove unused view engines and language

In next post of the series, we will discuss five more tips which will work as a performance booster for the applications.
 
Cheers
Brij