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 { get; set; }
/// <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 == null) throw 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;
}
}
}
}
// 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 { get; set; }
/// <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 == null) throw 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(" />");
}
}
}
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 生成模块配置文件。