Best way to shave 4 secs off of first page load?

Topics: Business Logic Layer
Aug 12, 2011 at 2:40 PM

Hi All,

I just started working with BlogEngine.Net and it's a pretty cool system. Love the way you all did theming and the over all architecture is pretty rockin. This is my first foreay into open source and so far I like what I see. Being and open source newbie I need pointers on how to best contribute.

As my first minor contribution, I decided to see why the system takes several seconds to serve up the the first page request after a recycle. Turns out we could shave off about 4 seconds (dev box timings) from the initial page load by making a few tweaks to the load extensions process.

The comments for the Utils.cs GetCompiledExtensions() method indicate that it only runs through the code assemblies market with the “BlogEngineExtension“ AssemblyConfiguration attribute however the actual implementation simply checks for the presence of the AssemblyConfiguration attribute but does not check that it contains the “BlogEngineExtension“ value. This results in the method returning all 15 assemblies in the Bin folder rather than the few that might actually contain BlogEngine.Net extensions. This causes all of these assemblies (System.Web.Razor.dll, etc) to get reflected upon by the LoadExtensions() method to look for extensions (a time consuming process).

Methods involved are all in Utils.cs

LoadExtensions() -> CodeAssemblies() -> GetCompiledExtensions().

Initially I resolved this issue by tweaking LoadExtensions() to only look for extensions in the assembly if it’s name contained (in lower case) app_code or blogengine. This works great and reduces the time it takes for the LoadExtensions() from 4.9 secs to .9 secs on my machine. But given the comments in the code, I wonder if it wouldn’t be better to set the AssemblyConfiguration value to “BlogEngineExtension“ for all the assemblies that might contain extensions (e.g. BlogEngine.Core.dll), and modify the GetCompiledExtensions() to actually check for that value.

The only problem I see with this approach is that the primary distribution for is as a website project which gets compiled on the fly at runtime and I’m not familiar with setting AssemblyConfiguration values in that situation. Personally, I work with BE as a Web Application Project so that I can precompile the dll for the web layer. And in that situation setting the AssemblyConfiguration to “BlogEngineExtension” attribute is a snap. Know any reason why a website project can’t have and AssemblyConfiguration attribute set? Do you like the idea of using the AssemblyConfiguration attribute like this? or do you prefer my quick and dirty approach of just checking the name of the dll before reflecting on it for extensions?

Either way, shaving 4 seconds off the initial load time makes things a little sweeter.



PS: Sorry to make my first post so long :-)

Aug 12, 2011 at 6:15 PM
Edited Oct 24, 2011 at 8:38 PM

Sounds good Ron !!!

So how exactly did you make it to check for Extensions?

Would like to apply this to my site too :)

Need detail step by step instructions on how to do this.

Great work !!!

Post length is ok great job explaining :)




Brian Davis

Java Blog

Aug 12, 2011 at 6:53 PM

 Hey Brian,

Thanks for the atta boy.  I'm not sure which of the two ways the head developer for this project will want to go, but for a quick and dirty fix, you simply need to replace the LoadExtensions() method in the BlogEngine.Core project with the one below.  Each line I have changed is marked with "//Mod RonC Added".  You then need to recompile the project to produce a new BlogEngine.Core.dll file that needs placed in your website's Bin directory.  The only thing that makes this approach a "hack" is that with this change blog engine will only recognize extensions that have been placed in the App_Code/Extensions folder or ones that have been compiled into a dll which contain blogengine in the name.  The other approach I proposed is more robust, but not sure if it's worth it, kinda depends on the architectual direction of the project.


/// <summary>
        /// Run through all code assemblies and creates object
        ///     instance for types marked with extension attribute
        /// </summary>
        public static void LoadExtensions()
	   DateTime start = DateTime.Now;							//Mod RonC Added to time code
	  var codeAssemblies = CodeAssemblies();

            var sortedExtensions = new List<SortedExtension>();

            foreach (Assembly a in codeAssemblies)
		//Mod RonC Added additional conditional so that only the dlls that may
		//         contain extension are inspected.  This speads up the load time
		//         of the first page request by several seconds. 
		//         i.e. reduced the time spent in this method from 4.9 secs to .9 secs
		string lowerName = a.ManifestModule.Name.ToLower();						//Mod RonC Added
		if (lowerName.IndexOf("app_code") >= 0 || lowerName.IndexOf("blogengine") >= 0) {			//Mod RonC Added
			var types = a.GetTypes();

			Type extensionsAttribute = typeof(ExtensionAttribute);

				from type in types
				let attributes = type.GetCustomAttributes(extensionsAttribute, false)
				from attribute in attributes
				where (attribute.GetType() == extensionsAttribute)
				let ext = (ExtensionAttribute)attribute
				select new SortedExtension(ext.Priority, type.Name, type.FullName));

				(e1, e2) =>
				e1.Priority == e2.Priority
					? string.CompareOrdinal(e1.Name, e2.Name)
					: e1.Priority.CompareTo(e2.Priority));

			foreach (var x in sortedExtensions.Where(x => ExtensionManager.ExtensionEnabled(x.Name))) {
		}								//Mod RonC Added

            // initialize comment rules and filters

	   TimeSpan span = DateTime.Now.Subtract(start);					//Mod RonC Added to time code