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 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 level as below
We can see that request is first received by http.sys so if it is cached at kernel level, then we can save most of the time spent on server as http.sys is a http listener which sits in OS kernel and listens the request directly from TCP layer. We can save all the time spent IIS/ASP.NET pipeline, page lifecycle, our custom code, time taken in DB etc. Let’s see how we can implement it.
a) Go to IIS and select the web site.
b) Click on Output Cache icon on right under IIS section
c) In right panel, under Actions click on Add. Following dialog will open
Here in red encircled area, we need to define that the file extensions which we want to cache at 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 limitation 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 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 similar way many feature are implemented as HTTP Module which are 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 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 over it. After changing thoroughly test it before moving ahead.
3- Remove unused Modules– Each request has go 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 the each modules, processed by the handler then again come though 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 to add configuration in web.config as
<system.webServer>
<modules>
<removename="FormsAuthentication" />
<removename="DefaultAuthentication" />
<removename="OutputCache" />
<removename="AnonymousIdentification" />
<removename="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 different number when use 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
<modulesrunAllManagedModulesForAllRequests="true">
It means all the modules would be running for all the request coming to 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 adding extra overheads. 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 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 writing anything in the folder c:\inetpub\wwwroot. - There is a file watcher looks into the folder and if there is 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 couple of entries in each request, then 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 add our own custom view engines as well. Let’s create a default MVC application and try to return a view which does not exists in the solution. Now when we run this applications 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 solution. So we should remove all the extra View Engines. We need to add following code in Application_Startmethodwhich is available in Global.asax.
// Removing all the view engines
ViewEngines.Engines.Clear();
//Add Razor Engine (which we are using)
ViewEngines.Engines.Add(newRazorViewEngine());
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
publicclassMyCustomViewEngine : RazorViewEngine
{
public MyCustomViewEngine()
{
base.AreaViewLocationFormats = newstring[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml"};
base.AreaMasterLocationFormats = newstring[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml" };
base.AreaPartialViewLocationFormats = newstring[] { "~/Areas/{2}/Views/{1}/{0}.cshtml","~/Areas/{2}/Views/Shared/{0}.cshtml"};
base.ViewLocationFormats = newstring[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
base.MasterLocationFormats = newstring[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
base.PartialViewLocationFormats = newstring[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
base.FileExtensions = newstring[] { "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