CAB 預設模組裝載器中的Bug

來源:互聯網
上載者:User
        前段時間在弄CAB (Composite UI Application Block), 按著書上寫的方法寫了一個模組workitem extension 擴充類。當被擴充的workitem的run方法被調用的是時候,擴充類所重寫的方法老是沒有被調用。書上說可以我測試卻不可以,搞得那天好心煩。設斷點調試,明明看到workitemExtensionService 裡面註冊了我的那個extension。 extension 裡面的OnRunStarted就是沒有被調用到,我崩潰了。 後來沒有辦法去看CAB的源碼,檢查了一個晚上終於發現了一個天大的秘密, 這是一個BUG!!!!!!!!
        我們來看一下CAB的預設moduleloader :        private void InnerLoad(WorkItem workItem, IModuleInfo[] modules)
        {
            if (modules.Length == 0)
                return;

            LoadAssemblies(modules);
            List<ModuleMetadata> loadOrder = GetLoadOrder();

            foreach (ModuleMetadata module in loadOrder)
                module.LoadServices(workItem);

            foreach (ModuleMetadata module in loadOrder)
                module.InitializeModuleClasses(workItem);

            foreach (ModuleMetadata module in loadOrder)
                module.InitializeWorkItemExtensions(workItem);

            foreach (ModuleMetadata module in loadOrder)
                module.NotifyOfLoadedModule(OnModuleLoaded);
        }

       
        模組裝載的時候Load方法會先檢查一下傳進來的參數有沒有null值這些問題, 然後轉而調用到上面的這個 InnerLoad方法來裝載模組。這個方法依次的 裝載服務、 初始化模組、 初始化workitem extension、 然後觸發模組裝載完畢事件....

        起初我懷疑我的workitemextension 掛鈎到workitem裡面的時機晚了, 果然不出我所料。 我們看一下 ModuleMetaData 類的 InitializeModuleClasses 方法            public void InitializeModuleClasses(WorkItem workItem)
            {
                if (modulesInitialzed)
                    return;

                modulesInitialzed = true;
                EnsureModuleClassesExist(workItem);

                try
                {
                    foreach (IModule module in moduleClasses)
                    {
                        module.Load();

                        if (traceSource != null)
                            traceSource.TraceInformation(Properties.Resources.ModuleStartCalled, module.GetType());
                    }
                }
                catch (FileNotFoundException ex) { ThrowModuleReferenceException(ex); }
                catch (Exception ex) { ThrowModuleLoadException(ex); }
            }

       而模組的InitializeModuleClasses 方法竟然調用了 IModule.Load() 方法!! 也就是說如果我在所 重寫的 ModuleInit.Load() 方法裡面開始我的邏輯的話, 此時workitemextension 還沒有被初始化,還沒有掛鈎到所擴充的workitem裡面!!!     而CAB附帶的幾個quick start 卻恰恰在重寫的ModuleInit.Load()方法裡面開始邏輯,也就是說在模組裝載還沒有完全完成的時候就已經開始邏輯了!! 嚴重誤導,嚴重浪費了我的時間......

       看來要自己找方法解決了。那個NotifyOfLoadedModule 是最後的步驟, 這個步驟會觸發 ModuleLoader.Loaded 事件。 這才是真正的裝載完畢! 於是我改為在 ModuleLoaded 的loaded 事件發生的時候開始我寫的邏輯。
       貼一下我寫的代碼:    public class PressureExplorerModuleInit : ModuleInit
    {
        private WorkItem shellRootWorkItem;

        // the root work item of the shell will be given by constructor injection
        [InjectionConstructor]
        public PressureExplorerModuleInit(
            [ServiceDependency] 
            WorkItem shellRootWorkItem)
        {
            this.shellRootWorkItem = shellRootWorkItem;
            shellRootWorkItem.Services.Get<IModuleLoaderService>().ModuleLoaded += new EventHandler<Microsoft.Practices.CompositeUI.Utility.DataEventArgs<LoadedModuleInfo>>(PressureExplorerModuleInit_ModuleLoaded);
        }

        private void PressureExplorerModuleInit_ModuleLoaded(object sender, Microsoft.Practices.CompositeUI.Utility.DataEventArgs<LoadedModuleInfo> e)
        {
            if (e.Data.Assembly == System.Reflection.Assembly.GetExecutingAssembly())
                Loaded();
        }

        private void Loaded()
        {
            // start the peWorkItem after the module is fully loaded by calling run method
            PEWorkItem peWorkItem = shellRootWorkItem.WorkItems.AddNew<PEWorkItem>("PEWorkItem");
            peWorkItem.Run();
        }
    }

       至此還沒有結束,雖然那我的問題解決了, 但是我還是想到網上別人有什麼更好的解決方案。 然後我找到了一篇文章有關新的 new module loader for CAB, 此模組裝載器修正了我所說的這個bug, 還提供了一些很有用的新功能:

Towards the end of the Smart Client Software Factory project, we
wanted to be able to support a more comprehensive module loader system
for CAB applications. Our goals were:

    1. Support grouping modules together into logical "sections" which
represented groups of functionality. These groups might be things like
"layout", "services", "applications", etc.
    2. Allow dependencies to be expressed between these sections (i.e., make
sure you load all the layout modules before you load the application
modules).
    3. Allow dependencies to be expressed in an external place instead of forcing them to be expressed in attributes on the assembly.
    4. Make it easier to provide transports for the profile catalog XML without having to write an entirely new enumerator.
    5. If possible, preserve backward compatibility with the new loader and
old enumerators, so that we could preserve effort people had putting
into writing their own enumerators.
    6. Fix a bug in the module loader that causes WorkItem extensions to be
registered too late to see WorkItems that were being created in the
module's Load method.

            1.  支援把模組按功能分組, 每一組模組(模組section)  代表一系列有關的功能 。 比如 “排版” 模組,“服務” 模組, “應用” 模組等等。
            2.  允許表達 section 之間的關係依賴性(耦合), 比如你可以確定 排版section 會在 應用section 裝載完畢之後再裝載。
            3.  允許在外部定義 關係依賴性,突破原先的只能在assembly attribute裡面定義的局限。
            4.  不需要寫整個 模組列舉程式來實現 profile catalog XML 的傳輸。
            5.  向後相容, 可以使用之前寫好的 模組列舉程式。
            6.  修正了我上面所描述的那個bug, 這個bug 使得 WorkItem extension 註冊晚了 ( 註冊聆聽workitem的RunStarted, Initialized等事件晚了 )。

        聯繫我們

        該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

        如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

        A Free Trial That Lets You Build Big!

        Start building with 50+ products and up to 12 months usage for Elastic Compute Service

        • Sales Support

          1 on 1 presale consultation

        • After-Sales Support

          24/7 Technical Support 6 Free Tickets per Quarter Faster Response

        • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.