zoukankan      html  css  js  c++  java
  • prism框架里module太多启动速度过慢

    一个基于prism框架desktop项目,总共有100多个module。程序启动的时候有几秒钟的delay。

    用的DirectoryModuleCatalog类从本地目录中装载module的程序集。

    附:DirectoryModuleCatalog装载部分源代码

    View Code
    //===================================================================================
    // Microsoft patterns & practices
    // Composite Application Guidance for Windows Presentation Foundation and Silverlight
    //===================================================================================
    // Copyright (c) Microsoft Corporation.  All rights reserved.
    // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
    // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
    // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    // FITNESS FOR A PARTICULAR PURPOSE.
    //===================================================================================
    // The example companies, organizations, products, domain names,
    // e-mail addresses, logos, people, places, and events depicted
    // herein are fictitious.  No association with any real company,
    // organization, product, domain name, email address, logo, person,
    // places, or events is intended or should be inferred.
    //===================================================================================
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Security.Policy;
    using Microsoft.Practices.Prism.Properties;

    namespace Microsoft.Practices.Prism.Modularity
    {
        /// <summary>
        
    /// Represets a catalog created from a directory on disk.
        
    /// </summary>
        
    /// <remarks>
        
    /// The directory catalog will scan the contents of a directory, locating classes that implement
        
    /// <see cref="IModule"/> and add them to the catalog based on contents in their associated <see cref="ModuleAttribute"/>.
        
    /// Assemblies are loaded into a new application domain with ReflectionOnlyLoad.  The application domain is destroyed
        
    /// once the assemblies have been discovered.
        
    /// 
        
    /// The diretory catalog does not continue to monitor the directory after it has created the initialze catalog.
        
    /// </remarks>
        public class DirectoryModuleCatalog : ModuleCatalog
        {
            /// <summary>
            
    /// Directory containing modules to search for.
            
    /// </summary>
            public string ModulePath { getset; }

            /// <summary>
            
    /// Drives the main logic of building the child domain and searching for the assemblies.
            
    /// </summary>
            protected override void InnerLoad()
            {
                if (string.IsNullOrEmpty(this.ModulePath))
                    throw new InvalidOperationException(Resources.ModulePathCannotBeNullOrEmpty);

                if (!Directory.Exists(this.ModulePath))
                    throw new InvalidOperationException(
                        string.Format(CultureInfo.CurrentCulture, Resources.DirectoryNotFound, this.ModulePath));

                AppDomain childDomain = this.BuildChildDomain(AppDomain.CurrentDomain);

                try
                {
                    List<string> loadedAssemblies = new List<string>();

                    var assemblies = (
                                         from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()
                                         where !(assembly is System.Reflection.Emit.AssemblyBuilder)
                                            && assembly.GetType().FullName != "System.Reflection.Emit.InternalAssemblyBuilder"
                                            && !String.IsNullOrEmpty(assembly.Location)
                                         select assembly.Location
                                     );

                    loadedAssemblies.AddRange(assemblies);

                    Type loaderType = typeof(InnerModuleInfoLoader);

                    if (loaderType.Assembly != null)
                    {
                        var loader =
                            (InnerModuleInfoLoader)
                            childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();
                        loader.LoadAssemblies(loadedAssemblies);
                        this.Items.AddRange(loader.GetModuleInfos(this.ModulePath));
                    }
                }
                finally
                {
                    AppDomain.Unload(childDomain);
                }
            }


            /// <summary>
            
    /// Creates a new child domain and copies the evidence from a parent domain.
            
    /// </summary>
            
    /// <param name="parentDomain">The parent domain.</param>
            
    /// <returns>The new child domain.</returns>
            
    /// <remarks>
            
    /// Grabs the <paramref name="parentDomain"/> evidence and uses it to construct the new
            
    /// <see cref="AppDomain"/> because in a ClickOnce execution environment, creating an
            
    /// <see cref="AppDomain"/> will by default pick up the partial trust environment of 
            
    /// the AppLaunch.exe, which was the root executable. The AppLaunch.exe does a 
            
    /// create domain and applies the evidence from the ClickOnce manifests to 
            
    /// create the domain that the application is actually executing in. This will 
            
    /// need to be Full Trust for Composite Application Library applications.
            
    /// </remarks>
            
    /// <exception cref="ArgumentNullException">An <see cref="ArgumentNullException"/> is thrown if <paramref name="parentDomain"/> is null.</exception>
            protected virtual AppDomain BuildChildDomain(AppDomain parentDomain)
            {
                if (parentDomain == nullthrow new System.ArgumentNullException("parentDomain");

                Evidence evidence = new Evidence(parentDomain.Evidence);
                AppDomainSetup setup = parentDomain.SetupInformation;
                return AppDomain.CreateDomain("DiscoveryRegion", evidence, setup);
            }

            private class InnerModuleInfoLoader : MarshalByRefObject
            {
                [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance""CA1822:MarkMembersAsStatic")]
                internal ModuleInfo[] GetModuleInfos(string path)
                {
                    DirectoryInfo directory = new DirectoryInfo(path);

                    ResolveEventHandler resolveEventHandler =
                        delegate(object sender, ResolveEventArgs args) { return OnReflectionOnlyResolve(args, directory); };

                    AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += resolveEventHandler;

                    Assembly moduleReflectionOnlyAssembly =
                        AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().First(
                            asm => asm.FullName == typeof(IModule).Assembly.FullName);
                    Type IModuleType = moduleReflectionOnlyAssembly.GetType(typeof(IModule).FullName);

                    IEnumerable<ModuleInfo> modules = GetNotAllreadyLoadedModuleInfos(directory, IModuleType);

                    var array = modules.ToArray();
                    AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= resolveEventHandler;
                    return array;
                }

                private static IEnumerable<ModuleInfo> GetNotAllreadyLoadedModuleInfos(DirectoryInfo directory, Type IModuleType)
                {
                    List<FileInfo> validAssemblies = new List<FileInfo>();
                    Assembly[] alreadyLoadedAssemblies = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies();

                    var fileInfos = directory.GetFiles("*.dll")
                        .Where(file => alreadyLoadedAssemblies
                                           .FirstOrDefault(
                                           assembly =>
                                           String.Compare(Path.GetFileName(assembly.Location), file.Name,
                                                          StringComparison.OrdinalIgnoreCase) == 0) == null);
                    
                    foreach (FileInfo fileInfo in fileInfos)
                    {
                        Assembly assembly = null;
                        try
                        {
                            assembly = Assembly.ReflectionOnlyLoadFrom(fileInfo.FullName);
                            validAssemblies.Add(fileInfo);
                        }
                        catch (BadImageFormatException)
                        {
                            // skip non-.NET Dlls
                        }
                    }

                    return validAssemblies.SelectMany(file => Assembly.ReflectionOnlyLoadFrom(file.FullName)
                                                .GetExportedTypes()
                                                .Where(IModuleType.IsAssignableFrom)
                                                .Where(t => t != IModuleType)
                                                .Where(t => !t.IsAbstract)
                                                .Select(type => CreateModuleInfo(type)));
                }

                private static Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
                {
                    Assembly loadedAssembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(
                        asm => string.Equals(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase));
                    if (loadedAssembly != null)
                    {
                        return loadedAssembly;
                    }
                    AssemblyName assemblyName = new AssemblyName(args.Name);
                    string dependentAssemblyFilename = Path.Combine(directory.FullName, assemblyName.Name + ".dll");
                    if (File.Exists(dependentAssemblyFilename))
                    {
                        return Assembly.ReflectionOnlyLoadFrom(dependentAssemblyFilename);
                    }
                    return Assembly.ReflectionOnlyLoad(args.Name);
                }

                [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance""CA1822:MarkMembersAsStatic")]
                internal void LoadAssemblies(IEnumerable<string> assemblies)
                {
                    foreach (string assemblyPath in assemblies)
                    {
                        try
                        {
                            Assembly.ReflectionOnlyLoadFrom(assemblyPath);
                        }
                        catch (FileNotFoundException)
                        {
                            // Continue loading assemblies even if an assembly can not be loaded in the new AppDomain
                        }
                    }
                }

                private static ModuleInfo CreateModuleInfo(Type type)
                {
                    string moduleName = type.Name;
                    List<string> dependsOn = new List<string>();
                    bool onDemand = false;
                    var moduleAttribute =
                        CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
                            cad => cad.Constructor.DeclaringType.FullName == typeof(ModuleAttribute).FullName);

                    if (moduleAttribute != null)
                    {
                        foreach (CustomAttributeNamedArgument argument in moduleAttribute.NamedArguments)
                        {
                            string argumentName = argument.MemberInfo.Name;
                            switch (argumentName)
                            {
                                case "ModuleName":
                                    moduleName = (string) argument.TypedValue.Value;
                                    break;

                                case "OnDemand":
                                    onDemand = (bool) argument.TypedValue.Value;
                                    break;

                                case "StartupLoaded":
                                    onDemand = !((bool) argument.TypedValue.Value);
                                    break;
                            }                           
                        }
                    }

                    var moduleDependencyAttributes =
                        CustomAttributeData.GetCustomAttributes(type).Where(
                            cad => cad.Constructor.DeclaringType.FullName == typeof(ModuleDependencyAttribute).FullName);

                    foreach (CustomAttributeData cad in moduleDependencyAttributes)
                    {
                        dependsOn.Add((string) cad.ConstructorArguments[0].Value);
                    }

                    ModuleInfo moduleInfo = new ModuleInfo(moduleName, type.AssemblyQualifiedName)
                                                {
                                                    InitializationMode =
                                                        onDemand
                                                            ? InitializationMode.OnDemand
                                                            : InitializationMode.WhenAvailable,
                                                    Ref = type.Assembly.CodeBase,
                                                };
                    moduleInfo.DependsOn.AddRange(dependsOn);
                    return moduleInfo;
                }
            }
        }
    }

    初步怀疑是在这里花费了太多的时间。

    解决方式:

    准备使用xaml文件来存储modules的配置信息。第一次启动程序当模块装载成功以后,创建一个xaml配置文件。

    以后启动程序不再遍历目录,之间从xaml文件读取配置信息。

    代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Practices.Prism.Modularity;
    using System.IO;

    namespace ModularityWithUnity.Desktop
    {
        public class ModuleCatalogConfigXAML
        {
            private const string SPACE_STRING_4 = "    ";
            private const string SPACE_STRING_8 = "        ";
            private ModuleCatalog moduleCatalog;
            private StringBuilder sb;

            public ModuleCatalogConfigXAML(ModuleCatalog moduleCatalog)
            {
                sb = new StringBuilder();
                this.moduleCatalog = moduleCatalog;
            }

            public void GenerateXAMLConfigFile(string fileFullPath)
            {
                BuildHeader();
                BuildGroups();
                BuildByGroupless();
                BuildFooter();
                SaveAsFile(fileFullPath, sb.ToString());
            }

            private static void SaveAsFile(string savedPath, string content)
            {
                
                using (StreamWriter sw = File.CreateText(savedPath))
                {
                    sw.Write(content);
                }
            }

            private void BuildHeader()
            {
                sb.AppendLine("<Modularity:ModuleCatalog xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"");
                sb.AppendLine(SPACE_STRING_8 +"xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"");
                sb.AppendLine(SPACE_STRING_8 + "xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"");
                sb.AppendLine(SPACE_STRING_8 + "xmlns:Modularity=\"clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism\">");

            }

            private void BuildFooter()
            {
                sb.AppendLine("</Modularity:ModuleCatalog>");
            }

            private void BuildGroups()
            {
                foreach (var group in moduleCatalog.Groups)
                {
                    BuildByGroup(group);
                }
            }

            private void BuildByGroup(ModuleInfoGroup group)
            {
                //IEnumerable<ModuleInfoGroup> groups = this.moduleCatalog.Groups;
                sb.AppendLine(SPACE_STRING_4 + "<Modularity:ModuleInfoGroup ");
                if (!string.IsNullOrEmpty(group.Ref))
                {
                    sb.Append(" Ref=\"" + group.Ref + "\"");
                }

                sb.Append(" InitializationMode=\"" + group.InitializationMode.ToString() +"\">");
                IEnumerator<ModuleInfo> moduleInfos = group.GetEnumerator();
                
                while(moduleInfos.MoveNext())
                {
                    BuildModule(moduleInfos.Current,SPACE_STRING_8);
                }
            }

            private void BuildByGroupless()
            {
                IEnumerable<ModuleInfo> groupLessModules = this.moduleCatalog.Items.OfType<ModuleInfo>();
                foreach (var moduleInfo in groupLessModules)
                {
                    BuildModule( moduleInfo,SPACE_STRING_4);
                }
            }

            private void BuildModule(ModuleInfo moduleInfo,string space)
            {
                sb.AppendLine(space + "<!-- Module info without a group -->");

                string content = space + "<Modularity:ModuleInfo ";

                
                if (!string.IsNullOrEmpty(moduleInfo.Ref))
                {
                    content += " Ref=\"" + moduleInfo.Ref + "\"";
                }

                if (!string.IsNullOrEmpty(moduleInfo.ModuleName))
                {
                    content += " ModuleName=\"" + moduleInfo.ModuleName + "\"";
                }

                content += " ModuleType=\"" + moduleInfo.ModuleType + "\" >";

                sb.AppendLine(content);

                if (moduleInfo.DependsOn != null && moduleInfo.DependsOn.Count>0)
                {
                    sb.AppendLine(space + SPACE_STRING_4 + "<Modularity:ModuleInfo.DependsOn>");
                    foreach (var item in moduleInfo.DependsOn)
                    {
                        sb.AppendLine(space + SPACE_STRING_4 + SPACE_STRING_4 + "<sys:String>" + item + "</sys:String>");
                    }

                    sb.AppendLine(space + SPACE_STRING_4 + "</Modularity:ModuleInfo.DependsOn>");
                    sb.AppendLine(space + "</Modularity:ModuleInfo> ");
                }
               
                sb.AppendLine(space + "</Modularity:ModuleInfo> ");
                    //sb.Append(" />");
                
            }
        }
    }

    使用的时候:

    UnityBootstrapper

     1.虚方法CreateModuleCatalog 用来返回ModuleCatalog类。
      在此方法中添加逻辑如下:
    如果modules的配置文件已经存在,则通过配置文件来生成ModuleCatalog.
    2.虚方法InitializeModules装载模块信息,在此方法后调用GenerateXAMLConfigFile 生成模块配置文件。
     

  • 相关阅读:
    UIApplication直接应用
    iOS开发之苹果开发者账号注册申请流程
    iOS开发之蓝牙使用-建立连接的
    Swift3.0 UICollectionView简单使用
    CSS网页菜单
    c#qq发邮件
    多文档界面的实现(DotNetBar的superTabControl)
    CE修改器:外挂制作高级技巧
    MariaDB 库的基本操作
    Python-使用PyQT生成图形界面
  • 原文地址:https://www.cnblogs.com/umlchina/p/2257205.html
Copyright © 2011-2022 走看看