How to Set Up a Kentico Development Environment with Full Source Code Properly
In this article, you will find out how to use a full Kentico source-code project to its maximum potential. I’ll share some tips on how to set the environment for faster development, how to apply hotfixes, and what to do for a successful breakpoint interception.
(The information in this article applies to a full source code license only.)
Having access to a full source code license gives you two main advantages:
- You can study Kentico internals to confirm what’s really happening inside
- You can override the core of the Kentico platform to your specific needs
As an administrator or a QA engineer, you have the option to verify that a hotfix can be safely applied to a business-critical website. Or you may wish to verify that a hotfix works well with the customizations of the Kentico platform made by your developers earlier in the development process.
While debugging the source code project, the most common problem you might encounter is ending up with Visual Studio not catching your breakpoints and saying, "The breakpoint will not currently be hit. No symbols have been loaded for this document."
To get this sorted out, we’ll have to review some core .NET development skills alongside commonly-used Kentico conventions.
The mentioned .NET skills involve:
- Knowledge of the dependency system in Visual Studio solutions
- Knowledge of how the ASP.NET runtime uses and compiles assemblies in your solution
- Knowledge of what Visual Studio does to allow you to debug
- Optional: knowledge of the differences between "website" and "web application" projects
I will shed some light on following Kentico conventions:
- How and why Kentico DLL files are moved around during the build of the solution
- How hotfixes should be applied correctly
- What the appropriate method of starting Kentico from within Visual Studio is
Quick Overview of the Source Code Preparation Process
If you’re not familiar with the process of running basic (non-hotfixed) source code projects, definitely make sure to follow the instructions in the Instructions.txt file in the solution’s root folder. Most importantly, this will tell you how to set a private key to sign the assemblies properly.
Applying the hotfix is a trickier process. In the case of a full source code, the hotfix needs to be applied manually (i.e., not via our Kentico Installation Manager (KIM) utility). Once you get the proper hotfix archive, the hotfixing process requires more than just copying the contents to the CMS folder.
First of all, let’s look at what’s inside. After you unpack the main archive, you’ll get a folder that contains a Hotfix.exe file together with the Instructions.pdf file and other contents. Make sure to check out the instructions file. Run Hotfix.exe with the "/deploy" and "/path" parameters to get the correct files generated. Both Kentico 8.2 and 9.0 by default target the 4.5 framework. Personally, I use the following syntax:
.\Hotfix.exe /deploy=net45app /path=Dn45App
This will produce a "Dn45App" subfolder. Now is the time to copy its contents over to your solution folder. Continue following the instructions in that file and take a moment to repair all missing (or unrecognized) references in the solution.
In the case of Kentico 8.2, there is one additional step—to install a temporary vanilla clean 8.2 web application instance via KIM. You can install it without the database. Select the target 4.5 framework and set it as a "web application" project type. Once the instance gets installed, just overwrite your solution’s "/CMS" folder with the contents of the corresponding folder from your temporary instance. Without copying the contents, you wouldn’t be able to import our sample site templates. With version 9, you’re not required to copy anything.
Making your Development Faster
By default, Visual Studio uses IIS Express for the debugging of ASP.NET applications. My recommendation is to choose the ordinary IIS instead. You’ll still be able to use F5 (if you prefer), but it is much better to attach to the already-running w3wp.exe process instead. The benefit is that dynamic JIT compilations may kick in less often, and you’ll be able to browse Kentico even outside of a running debugging session.
To do so, go to the "CMSApp" project properties, then go to the "Web" tab. Choose "Local IIS", set a URL, and press "Create Virtual Directory".
An even better option is to configure it in the IIS Manager instead. With this approach, you’ll be able to set your own application pool (other than the "DefaultAppPool"). This has lots of advantages.
I recommend creating an IIS "site" instead of a "virtual application" or "virtual directory". This way, you can set multiple IIS bindings and DNS records (or "hosts" file records) with the following pattern:
http://kenticosolutionfolder.myhostname/
http://dancinggoat.kenticosolutionfolder.myhostname/
http://corporatesite.kenticosolutionfolder.myhostname/
http://mynewsite.kenticosolutionfolder.myhostname/
All of them point to the same solution folder. This will allow you to switch between sites quickly. With the "site" in place, you can also use multiple IP addresses rather than just host headers and develop with SSL enabled.
Last but not least, if there were no changes made to the project libraries, I would recommend avoiding using Ctrl+Shift+B in favor of building the "CMSApp" project (or the "CMSApp_AppCode" project). It will save you a lot of compilation time.
You can also deploy the Roslyn NuGet package to all of the projects in the solution.
How Kentico Full Source Code Is Built in Visual Studio
Here's a bit of background for beginners. Visual Studio projects usually have their dependencies set via the project references system. Apart from that, solution-level dependencies can also be set via the Project Dependencies window. A project with dependents also can depend on other projects, and dependencies do not necessarily have to be strictly hierarchical. The CRL only requires avoiding circular dependencies. Therefore, dependencies can sometimes form a complex graph.
The Kentico solution consists of more than 100 projects that have nested dependencies. The solution does not follow the "single output folder" pattern, meaning each project’s output folder gets populated with DLL files of each directly or indirectly dependent project. The following paragraph will clarify why this is important.
You’ve surely noticed the "/Lib" folder in the solution. Its role is to supply DLL files of all projects (and third-party libraries). The reason for this is that, in some cases, the compiler may prevent building some of the DLL files to the output folder of the "CMSApp" and "CMSApp_AppCode" projects. Therefore, these projects have a post-build event set with the following commands:
xcopy "$(ProjectDir)..\Lib\*" "$(TargetDir)" /y /r
xcopy "$(ProjectDir)..\Lib\Azure\*" "$(TargetDir)" /y /r
The DLL files get copied to the output folder every time one of the two projects is built.
However, the full source code self-extracting archive is shipped with the "/Lib" folder containing the DLL files without any hotfix applied. The result is that, even though you apply your hotfix correctly and build your hotfixed solution, you’ll end up with the two aforementioned projects referencing old platform DLL files. In the next paragraphs, you’ll see how to get around this.
Preparing for Successful Breakpoint Interception
Let me give you some background on .NET first.
In order to get a .NET application debugged, it needs to be built in a Debug configuration. Visual Studio then uses PDB files containing so-called symbols with C# identifiers and their mappings to the running assembly. The point is that symbols get generated from the current debugging session while the DLL files of the running assembly don’t necessarily have to.
The old platform DLL files mentioned in the previous section are the root cause of the "No symbols …" message mentioned above.
You should pick the newest version of each DLL file from the other projects and copy it to the "/Lib" folder. It will then be moved over to the output folder of the web projects via the post-build events (see above).
To ease that tedious task, I’ve written a PowerShell cmdlet that searches for all "CMS.*.dll" files deep within the solution folder, creates a distinct set of all occurrences (they exist in multiple copies), and always copies the newest one to the "/Lib" folder for you. Please note that hotfixed DLL files have the same assembly version, so the script must take only the filesystem update date into account. If you make an old DLL file look newer, it will get copied instead of the proper file. Here is the download link to the PowerShell cmdlet.
The advantage of the script is that you can also put it in the solution folder and run it automatically as part of the post-build events. Simply put the call before the aforementioned two "xcopy" statements:
powershell.exe -File $(SolutionDir)Replace-KenticoLibDlls.ps1 -SolutionDir $(SolutionDir)
If you want a bit more control, you can run the script manually with syntax:
.\Replace-KenticoLibDlls.ps1 –SolutionFolder “C:\inetpub\kenticosolutionfolder\”
There are a few things to note about the manual run. The trailing backslash character must be present at the end of the path. It is required by Visual Studio macros. Also, note that you should build your "CMSApp" project after manually running the script. In Windows 7 and Windows Server 2008, you may notice some "Unable to index into an object of type System.Collections.DictionaryEntry." error messages. In my testing, the files got copied correctly, despite the errors. But just to be sure, I would certainly recommend checking the dates on your "CMS.*.dll" files in the "Lib" folder.
Now you can navigate to your basic URL (e.g., http://kenticosolutionfolder.myhostname/ in the above examples) or hit F5 to start the database installation wizard.
The "Website" Project Type
If you have an older Kentico project, one part of the upgrade process may be the testing of its functionality with your modified Kentico platform. If it is a "website" project type, you should convert it into a "web application" project type first. You can read more about it in an older article by our CTO, Martin Hejtmanek, and in the official MSDN article.
The conversion is a very lengthy process, so don’t be surprised. Sometimes it may make sense to upgrade the "website" project, export the site in the "Sites" application, and import it into the full source code instance instead.
Troubleshooting
If breakpoints still can’t be hit, check the Visual Studio "Configuration Manager" tool if projects have the "Debug" configuration set.
Next, display the "Modules" window, right-click the module and view the detailed filesystem path to the current DLL file in the ASP.NET temporary folder (or in a different probing path). If you see the "PDB does not match image" message, go to that folder, inspect the last update date of the DLL file, and search for such file (with such an update date) in your solution folder. This will tell you which file was copied to the ASP.NET temporary folder. Knowing which specific file was copied helps in narrowing down the root cause.
If you can’t determine the root cause—ASP.NET runtime and Visual Studio can be tricky sometimes—you can try the following: stop the application pool, clean the solution, check if all the projects generate DLL files, rebuild, re-run the script, delete the ASP.NET temporary folder, build the "CMSApp" project, and run the debug again.
Summary
With this article, you should be able to have a fresh hotfix applied to your full source code solution any time. By following these tips, your Kentico build should be compiled faster, and Visual Studio should be able to catch most of your breakpoints. You should also be able to switch between Kentico sample sites and your own site without stopping and starting them again.