Initialization in EPiServer CMS 5
This is the first part of a three part series covering initialization in EPiServer CMS. This is intended to give you an overview of the current (CMS 5) state, while "Introducing the new Initialization System in EPiServer CMS 6" and "The new Initialization System - Advanced Topics" will cover new ground.
Such a simple task as starting your application actually requires a lot of support from your framework. In this case I use the term framework in a very wide sense, including the .NET Framework, IIS and the EPiServer CMS.
Just to list a few requirements:
- The startup should be transparent to your application.
You should not have to care about the specifics of the EPiServer product, but treat the startup as if your application runs under plain ASP.NET.
- If something goes wrong during the startup the application should fail consistently until the error condition goes away.
- You should be able to plug in your own or other third party modules as part of the regular startup handling.
This means that hacking around with HTTP modules and attaching to BeginRequest etc should not be required, nor using the PlugInAttribute system (although that is a reasonably clean approach).
- The startup should be able to make sure that different modules are initialized and started in the right order.
- Startup should be fast.
Another sore point is the discrepancy between EPiServer CMS and EPiServer Community. These products are now moving closer together by virtue of the EPiServer Framework which is also the place for the new startup and initialization code.
Some background on EPiServer CMS initialization
In EPiServer CMS 5 we moved to a configuration system with where we support multiple site definitions in a single configuration file. Initially we use the IIS instance ID (or actually the Metabase path) to determine which site definition an EPiServer instance should use. We soon moved to use host name information from the incoming request instead, since using the Metabase path caused problems when running in load balanced environments with shared files (you had to make sure that the IIS instance ID was identical on all machines, which was a pain).
One drawback of using the host name of an incoming request is that we have to have an actual request to be able to determine the site section to use. Depending on the IIS version and some other factors this information was not always available as early as we would have wanted. This is what prevents you from calling most of the EPiServer API:s from within the Application_Start method.
EPiServer CMS 5 supports attaching to event handlers from within Application_Start, but not much more. The rest of the code that you want to run on application startup has to be started by the FirstBeginRequest event, which was added to help address the Application_Start problem.
Unfortunately this breaks the transparency requirement above.
How to initialize your custom module
As noted above you can attach to the FirstBeginRequest event, but that requires you to add code to Application_Start which is usually not desirable for a re-usable module since it will require source code changes to the solution where you want to add the module.
Another approach is to write an HttpModule and attach to the FirstBeginRequest event from the HttpModules Init method. This is a cleaner approach but requires changes to the web.config file (adding the HttpModule).
A third approach that has become quite widespread is to make use of the PlugIn system in EPiServer CMS. When you create a custom PlugIn attribute (by inheriting from the EPiServer.PlugIn.PlugInAttribute) and add a static Start method to that class, the Start method will be called by the EPiServer CMS plugin system at startup. The PlugIn system will scan all files in the bin folder and therefore you simply have to drop an assembly into the bin folder for this to work. See one of the many excellent blog articles that has bee written about this approach, for example http://labs.episerver.com/en/Blogs/Allan/Dates/112230/3/When-and-Where-to-attach-DataFactory-Event-Handlers/
Using the plugin system just to get your code to initialize is however somewhat of a hack, although I consider it to be a "clean" hack (if such a thing exists).
There are also several blogs about using the PlugInAttribute approach together with Virtual Path Providers to give you a true single assembly module deployment. See for example http://labs.episerver.com/en/Blogs/Johano/Dates/2008/6/EPiServer-PlugIns-in-one-single-dll/ for more information on this subject.
To summarize: There are several ways to get your custom initialization code to execute, but none of them are truly designed to handle initialization in a robust way. The main issue is usually that a failure condition on startup will only be seen by the person issuing the first web request to the web application.
Soon to follow is "Introducing the new Initialization System in EPiServer CMS 6"