/// <summary>
        /// To be called in Page_Load():
        /// Load the M object from the storage, propagate it to all sub-controls
        /// and recursively hide them all below the main control.
        /// Also sets a global reference to the main control in IIE for testing.
        /// </summary>
        /// <typeparam name="M"></typeparam>
        /// <param name="controlStorage"></param>
        public static void LoadMain <M>(this IStorageControl <M> controlStorage)
            where M : class, new()
        {
            controlStorage.ClearIfRequested();

            Guid sessionOverride;

            if (!controlStorage.IsPostBack && Guid.TryParse(controlStorage.Request.QueryString["session"], out sessionOverride))
            {
                controlStorage.Main = Main.LoadMain <M>(sessionOverride);
            }
            else
            {
                switch (controlStorage.GetStorage())
                {
                case Storage.ViewState:
                    controlStorage.Main = (M)controlStorage.ViewState[controlStorage.StorageID()];
                    break;

                case Storage.Session:
                    controlStorage.Main = (M)controlStorage.Session[controlStorage.StorageID()];
                    break;

                case Storage.Database:
                    var cookie = controlStorage.Request.Cookies[controlStorage.StorageID()];
                    if (cookie != null)
                    {
                        Guid session;
                        if (Guid.TryParse(cookie["session"], out session))
                        {
                            Func <byte[], byte[]> filter = null;
                            if (controlStorage.GetEncryptDatabaseStorage())
                            {
                                filter = x => Crypt.Decrypt(controlStorage.GetSecret(), x);     // closure
                            }
                            controlStorage.Main = Main.LoadMain <M>(session, filter);
                        }
                    }
                    break;
                }
            }

            if (controlStorage.Main == null)
            {
                controlStorage.Main = new M();
            }
            CurrentMain = controlStorage.Main;
            ControlRootExtension.SetRoot(controlStorage);

            controlStorage.PropagateMain(controlStorage.Main);
        }
        /// <summary>
        /// To be called at the end of OnPreRender():
        /// Persist the in this page life-cycle stage immutable Main object.
        /// </summary>
        /// <typeparam name="M"></typeparam>
        /// <param name="controlStorage"></param>
        public static void SaveMain <M>(this IStorageControl <M> controlStorage)
            where M : class, new()
        {
            var storage = controlStorage.GetStorage();

            Trace.Assert(controlStorage.Main != null, "SaveMain() without preceding LoadMain()");
            switch (storage)
            {
            case Storage.ViewState:
                controlStorage.ViewState[controlStorage.StorageID()] = controlStorage.Main;
                break;

            case Storage.Session:
                controlStorage.Session[controlStorage.StorageID()] = controlStorage.Main;
                break;

            case Storage.Database:
                Guid session = Guid.NewGuid();      // cannot exist in the database -> will get a new one on SaveMain()
                var  cookie  = controlStorage.Request.Cookies[controlStorage.StorageID()];
                if (cookie != null)
                {
                    Guid.TryParse(controlStorage.Request.Cookies[controlStorage.StorageID()]["session"], out session);
                }

                Func <byte[], byte[]> filter = null;
                if (controlStorage.GetEncryptDatabaseStorage())
                {
                    filter = x => Crypt.Encrypt(controlStorage.GetSecret(), x);     // closure
                }
                session = Main.SaveMain(controlStorage.Main, session, filter);

                var configDays = ConfigurationManager.AppSettings["DatabaseStorageExpires"];
                var days       = String.IsNullOrWhiteSpace(configDays) ? 1 : int.Parse(configDays);
                controlStorage.Response.Cookies[controlStorage.StorageID()]["session"] = session.ToString();
                controlStorage.Response.Cookies[controlStorage.StorageID()].Expires    = DateTime.Now.AddDays(days);
                break;
            }
        }