Skip to content
12 Tips To Increase the Performance of Your ASP.NET App – Part 1

12 Tips To Increase the Performance of Your ASP.NET App – Part 1

Building and hosting a web application on a web server is insanely easy with ASP.NET and IIS. However, many opportunities and hidden configurations can be tweaked to make it a high-performance web application. In this series post, we will discuss some of the most unused or ignored tricks that can be easily applied to any web application.

8min read

Building and hosting a web application on a web server is insanely easy with ASP.NET and IIS. However, many opportunities and hidden configurations can be tweaked to make it a high-performance web application. In this series post, we will discuss some of the most unused or ignored tricks that 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 applications faster. But most of the time, we don’t use it optimally, leaving some major benefits.  As each asp.net request goes through various stages, we can implement caching at multiple levels as below.

 request response

We can see that the 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 that sits in the OS kernel and listens to the request directly from TCP layer. We can save all the time spent on the 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 must define the file extensions we want to cache at the kernel. For the second encircled area, we need to select the checkbox. The third encircled area shows that there are three options provided to invalidate the cache. Based on our requirements, we can configure it.

Note – there are some limitations to overcaching at the kernel level. As all the features of IIS are implemented at the user level, we will not be able to leverage any of them. Refer to this MSDN article for a complete list of kernel caching that cannot be implemented.

2. Pipeline Mode (Available on IIS 7+)

Two pipeline modes are available at the application pool level: 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 that are implemented as modules in IIS, and in a similar way, many features are implemented as an HTTP Module, which is part of the ASP.NET Pipeline. In the classic mode, each request goes through the IIS pipeline and then the ASP.NET pipeline before getting served.

There are many features that are part of both pipelines, like Authentication, etc. In the case of Integrated mode, these two pipelines are merged into one, and all the modules (IIS and ASP.NET) are invoked from the single event as they come along, which reduces redundancy and is very helpful in the performance of an application.

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

edit app pool

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 the 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, is processed by the handler, and then comes 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;

This collection can be bound to any control, and it displays as:

It shows eighteen modules, some of which we may not be using, but each request has to go through these modules. So we can remove these modules from the pipeline. To remove a module, we 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 the 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 requests 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 it simply false at the 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

A file watcher looks into the folder and restarts the corresponding application pool if there are any changes in this folder. This feature is 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, 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 part of the MVC request life cycle and is responsible for finding the view and processing 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 that does not exist in the solution. Now, when we run this application, it 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, we are using the razor view engine, so it should not waste time looking at other aspx files because we already know that it will not be part of the solution. So we should remove all the extra View Engines.  We need to add the 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 know that it is looking for c# and vb files and says in our solutions, we have never used vb, so again, there is no use in 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 that make sense and are performance-friendly.

Conclusion

In this post, we have discussed the 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.

 

Request a Demo