.net 如何在Prism中控制模块初始化的顺序
我将Prism V2与DirectoryModuleCatalog一起使用,我需要按照一定的顺序初始化模块。所需的顺序由每个IModule实现的一个属性指定 这是因为在初始化每个模块时,它们会将视图添加到TabControl区域中,并且选项卡的顺序需要由模块作者确定和控制 顺序并不意味着依赖关系,而只是它们应该初始化的顺序。换句话说:模块A、B和C的优先级分别为1、2和3。B不依赖于a,它只需要在a之后加载到TabControl区域,这样我们就有了一个确定的、可控的选项卡顺序。而且,B在运行时可能不存在;因此它们将作为A,C加载,因为优先级应该决定顺序(1,3)。如果我使用ModuleDependency,那么模块“C”将无法加载它的所有依赖项 我可以管理如何对模块进行排序的逻辑,但我不知道将所述逻辑放在哪里。在引导程序中的AddModule()调用中,可以指定依赖项。所以,你可以说A依赖于B依赖于C,这将决定加载顺序.net 如何在Prism中控制模块初始化的顺序,.net,wpf,prism,.net,Wpf,Prism,我将Prism V2与DirectoryModuleCatalog一起使用,我需要按照一定的顺序初始化模块。所需的顺序由每个IModule实现的一个属性指定 这是因为在初始化每个模块时,它们会将视图添加到TabControl区域中,并且选项卡的顺序需要由模块作者确定和控制 顺序并不意味着依赖关系,而只是它们应该初始化的顺序。换句话说:模块A、B和C的优先级分别为1、2和3。B不依赖于a,它只需要在a之后加载到TabControl区域,这样我们就有了一个确定的、可控的选项卡顺序。而且,B在运行时可
您可以使用模块类上的
ModuleDependency
属性告诉加载程序您的模块依赖于其他模块:
[ModuleDependency("SomeModule")]
[ModuleDependency("SomeOtherModule")]
public class MyModule : IModule
{
}
您可以替换自定义类实例的默认IModuleInitializer,该自定义类不是在模块加载后立即初始化模块,而是将模块存储在模块列表中。加载所有模块后,您可以按照您想要的顺序初始化它们 如何做到这一点: 1) 在引导程序中,重写ConfigureContainer方法以替换MyModuleInitializer类实例的默认IModuleInitializer,同时使用名称(例如,defaultModuleInitializer)维护默认初始值设定项:
受保护的覆盖无效配置容器()
{
base.ConfigureContainer();
var defaultContainer=Container.Resolve();
RegisterInstance(“defaultModuleInitializer”,defaultContainer);
RegisterType(新的ContainerControlledLifetimeManager());
}
2) 创建MyModuleInitializer类,该类执行所需的storea all-then sort and initialize过程:
public class MyModuleInitializer : IModuleInitializer
{
bool initialModuleLoadCompleted = false;
IModuleInitializer defaultInitializer = null;
List<ModuleInfo> modules = new List<ModuleInfo>();
public MyModuleInitializer(IUnityContainer container)
{
defaultInitializer = container.Resolve<IModuleInitializer>("defaultModuleInitializer");
}
public void Initialize(ModuleInfo moduleInfo)
{
if(initialModuleLoadCompleted) {
//Module loaded on demand after application startup - use the default initializer
defaultInitializer.Initialize(moduleInfo);
return;
}
modules.Add(moduleInfo);
if(AllModulesLoaded()) {
SortModules();
foreach(var module in modules) {
defaultInitializer.Initialize(module);
}
modules = null;
initialModuleLoadCompleted = true;
}
}
private bool AllModulesLoaded()
{
//Here you check whether all the startup modules have been loaded
//(perhaps by looking at the module catalog) and return true if so
}
private void SortModules()
{
//Here you sort the "modules" list however you want
}
}
公共类MyModuleInitializer:IModuleInitializer
{
bool initialModuleLoadCompleted=false;
IModuleInitializer defaultInitializer=null;
列表模块=新列表();
公共MyModuleInitializer(IUnityContainer容器)
{
defaultInitializer=container.Resolve(“defaultModuleInitializer”);
}
公共无效初始化(ModuleInfo ModuleInfo)
{
如果(initialModuleLoadCompleted){
//应用程序启动后按需加载模块-使用默认初始值设定项
defaultInitializer.Initialize(moduleInfo);
返回;
}
modules.Add(moduleInfo);
如果(AllModulesLoaded()){
SortModules();
foreach(模块中的var模块){
defaultInitializer.Initialize(模块);
}
模块=空;
initialModuleLoadCompleted=true;
}
}
私有布尔AllModulesLoaded()
{
//在此检查是否已加载所有启动模块
//(可能通过查看模块目录)并返回true(如果是)
}
私有无效SortModules()
{
//在这里,您可以根据需要对“模块”列表进行排序
}
}
请注意,在加载所有启动模块之后,此类将恢复为仅调用默认初始值设定项。如果这不是您需要的,请适当地调整类。我通过使用ModuleDependency属性解决了这个问题,它工作起来很有魅力我不喜欢使用ModuleDependency的想法,因为这意味着当模块b不存在时,模块a不会加载,而实际上没有依赖。相反,我创建了一个优先级属性来装饰模块:
/// <summary>
/// Allows the order of module loading to be controlled. Where dependencies
/// allow, module loading order will be controlled by relative values of priority
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class PriorityAttribute : Attribute
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="priority">the priority to assign</param>
public PriorityAttribute(int priority)
{
this.Priority = priority;
}
/// <summary>
/// Gets or sets the priority of the module.
/// </summary>
/// <value>The priority of the module.</value>
public int Priority { get; private set; }
}
我创建了DirectoryModuleCatalog的新后代:
/// <summary>
/// ModuleCatalog that respects PriorityAttribute for sorting modules
/// </summary>
[SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog
{
/// <summary>
/// local class to load assemblies into different appdomain which is then discarded
/// </summary>
private class ModulePriorityLoader : MarshalByRefObject
{
/// <summary>
/// Get the priorities
/// </summary>
/// <param name="modules"></param>
/// <returns></returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
public Dictionary<string, int> GetPriorities(IEnumerable<ModuleInfo> modules)
{
//retrieve the priorities of each module, so that we can use them to override the
//sorting - but only so far as we don't mess up the dependencies
var priorities = new Dictionary<string, int>();
var assemblies = new Dictionary<string, Assembly>();
foreach (ModuleInfo module in modules)
{
if (!assemblies.ContainsKey(module.Ref))
{
//LoadFrom should generally be avoided appently due to unexpected side effects,
//but since we are doing all this in a separate AppDomain which is discarded
//this needn't worry us
assemblies.Add(module.Ref, Assembly.LoadFrom(module.Ref));
}
Type type = assemblies[module.Ref].GetExportedTypes()
.Where(t => t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal))
.First();
var priorityAttribute =
CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
cad => cad.Constructor.DeclaringType.FullName == typeof(PriorityAttribute).FullName);
int priority;
if (priorityAttribute != null)
{
priority = (int)priorityAttribute.ConstructorArguments[0].Value;
}
else
{
priority = 0;
}
priorities.Add(module.ModuleName, priority);
}
return priorities;
}
}
/// <summary>
/// Get the priorities that have been assigned to each module. If a module does not have a priority
/// assigned (via the Priority attribute) then it is assigned a priority of 0
/// </summary>
/// <param name="modules">modules to retrieve priorities for</param>
/// <returns></returns>
private Dictionary<string, int> GetModulePriorities(IEnumerable<ModuleInfo> modules)
{
AppDomain childDomain = BuildChildDomain(AppDomain.CurrentDomain);
try
{
Type loaderType = typeof(ModulePriorityLoader);
var loader =
(ModulePriorityLoader)
childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();
return loader.GetPriorities(modules);
}
finally
{
AppDomain.Unload(childDomain);
}
}
/// <summary>
/// Sort modules according to dependencies and Priority
/// </summary>
/// <param name="modules">modules to sort</param>
/// <returns>sorted modules</returns>
protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
{
Dictionary<string, int> priorities = GetModulePriorities(modules);
//call the base sort since it resolves dependencies, then re-sort
var result = new List<ModuleInfo>(base.Sort(modules));
result.Sort((x, y) =>
{
string xModuleName = x.ModuleName;
string yModuleName = y.ModuleName;
//if one depends on other then non-dependent must come first
//otherwise base on priority
if (x.DependsOn.Contains(yModuleName))
return 1; //x after y
else if (y.DependsOn.Contains(xModuleName))
return -1; //y after x
else
return priorities[xModuleName].CompareTo(priorities[yModuleName]);
});
return result;
}
}
public class AggregateModuleCatalog : IModuleCatalog
{
private List<IModuleCatalog> catalogs = new List<IModuleCatalog>();
/// <summary>
/// Initializes a new instance of the <see cref="AggregateModuleCatalog"/> class.
/// </summary>
public AggregateModuleCatalog()
{
this.catalogs.Add(new ModuleCatalog());
}
/// <summary>
/// Gets the collection of catalogs.
/// </summary>
/// <value>A read-only collection of catalogs.</value>
public ReadOnlyCollection<IModuleCatalog> Catalogs
{
get
{
return this.catalogs.AsReadOnly();
}
}
/// <summary>
/// Adds the catalog to the list of catalogs
/// </summary>
/// <param name="catalog">The catalog to add.</param>
public void AddCatalog(IModuleCatalog catalog)
{
if (catalog == null)
{
throw new ArgumentNullException("catalog");
}
this.catalogs.Add(catalog);
}
/// <summary>
/// Gets all the <see cref="ModuleInfo"/> classes that are in the <see cref="ModuleCatalog"/>.
/// </summary>
/// <value></value>
public IEnumerable<ModuleInfo> Modules
{
get
{
return this.Catalogs.SelectMany(x => x.Modules);
}
}
/// <summary>
/// Return the list of <see cref="ModuleInfo"/>s that <paramref name="moduleInfo"/> depends on.
/// </summary>
/// <param name="moduleInfo">The <see cref="ModuleInfo"/> to get the</param>
/// <returns>
/// An enumeration of <see cref="ModuleInfo"/> that <paramref name="moduleInfo"/> depends on.
/// </returns>
public IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)
{
var catalog = this.catalogs.Single(x => x.Modules.Contains(moduleInfo));
return catalog.GetDependentModules(moduleInfo);
}
/// <summary>
/// Returns the collection of <see cref="ModuleInfo"/>s that contain both the <see cref="ModuleInfo"/>s in
/// <paramref name="modules"/>, but also all the modules they depend on.
/// </summary>
/// <param name="modules">The modules to get the dependencies for.</param>
/// <returns>
/// A collection of <see cref="ModuleInfo"/> that contains both all <see cref="ModuleInfo"/>s in <paramref name="modules"/>
/// and also all the <see cref="ModuleInfo"/> they depend on.
/// </returns>
public IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
{
var modulesGroupedByCatalog = modules.GroupBy<ModuleInfo, IModuleCatalog>(module => this.catalogs.Single(catalog => catalog.Modules.Contains(module)));
return modulesGroupedByCatalog.SelectMany(x => x.Key.CompleteListWithDependencies(x));
}
/// <summary>
/// Initializes the catalog, which may load and validate the modules.
/// </summary>
public void Initialize()
{
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
}
}
/// <summary>
/// Adds a <see cref="ModuleInfo"/> to the <see cref="ModuleCatalog"/>.
/// </summary>
/// <param name="moduleInfo">The <see cref="ModuleInfo"/> to add.</param>
public void AddModule(ModuleInfo moduleInfo)
{
this.catalogs[0].AddModule(moduleInfo);
}
}
//
///ModuleCatalog,它尊重排序模块的PriorityAttribute
///
[SecurityPermission(SecurityAction.InheritanceDemand)、SecurityPermission(SecurityAction.LinkDemand)]
公共类PrioritizedDirectoryModuleCatalog:DirectoryModuleCatalog
{
///
///本地类将程序集加载到不同的appdomain中,然后将其丢弃
///
私有类ModulePriorityLoader:MarshallByRefObject
{
///
///获得优先权
///
///
///
[System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Performance”、“CA1822:MarkMembersAstatic”)、System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Reliability”、“CA2001:AvoidCallingProblemMaticMethods”、MessageId=“System.Reflection.Assembly.LoadFrom”)]
公共字典GetPriorities(IEnumerable模块)
{
//检索每个模块的优先级,以便我们可以使用它们覆盖
//排序-但前提是我们不会弄乱依赖关系
var priorities=newdictionary();
var assemblies=newdictionary();
foreach(模块中的模块信息模块)
{
如果(!assemblies.ContainsKey(module.Ref))
{
//由于意外的副作用,通常应立即避免装载,
//但由于我们是在一个单独的AppDomain中完成所有这些操作的,因此被丢弃
//这不必让我们担心
添加(module.Ref,Assembly.LoadFrom(module.Ref));
}
类型类型=程序集[module.Ref].GetExportedTypes()
其中(t=>t.AssemblyQualifiedName.Equals)(module.ModuleType,
/// <summary>
/// ModuleCatalog that respects PriorityAttribute for sorting modules
/// </summary>
[SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog
{
/// <summary>
/// local class to load assemblies into different appdomain which is then discarded
/// </summary>
private class ModulePriorityLoader : MarshalByRefObject
{
/// <summary>
/// Get the priorities
/// </summary>
/// <param name="modules"></param>
/// <returns></returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
public Dictionary<string, int> GetPriorities(IEnumerable<ModuleInfo> modules)
{
//retrieve the priorities of each module, so that we can use them to override the
//sorting - but only so far as we don't mess up the dependencies
var priorities = new Dictionary<string, int>();
var assemblies = new Dictionary<string, Assembly>();
foreach (ModuleInfo module in modules)
{
if (!assemblies.ContainsKey(module.Ref))
{
//LoadFrom should generally be avoided appently due to unexpected side effects,
//but since we are doing all this in a separate AppDomain which is discarded
//this needn't worry us
assemblies.Add(module.Ref, Assembly.LoadFrom(module.Ref));
}
Type type = assemblies[module.Ref].GetExportedTypes()
.Where(t => t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal))
.First();
var priorityAttribute =
CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
cad => cad.Constructor.DeclaringType.FullName == typeof(PriorityAttribute).FullName);
int priority;
if (priorityAttribute != null)
{
priority = (int)priorityAttribute.ConstructorArguments[0].Value;
}
else
{
priority = 0;
}
priorities.Add(module.ModuleName, priority);
}
return priorities;
}
}
/// <summary>
/// Get the priorities that have been assigned to each module. If a module does not have a priority
/// assigned (via the Priority attribute) then it is assigned a priority of 0
/// </summary>
/// <param name="modules">modules to retrieve priorities for</param>
/// <returns></returns>
private Dictionary<string, int> GetModulePriorities(IEnumerable<ModuleInfo> modules)
{
AppDomain childDomain = BuildChildDomain(AppDomain.CurrentDomain);
try
{
Type loaderType = typeof(ModulePriorityLoader);
var loader =
(ModulePriorityLoader)
childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();
return loader.GetPriorities(modules);
}
finally
{
AppDomain.Unload(childDomain);
}
}
/// <summary>
/// Sort modules according to dependencies and Priority
/// </summary>
/// <param name="modules">modules to sort</param>
/// <returns>sorted modules</returns>
protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
{
Dictionary<string, int> priorities = GetModulePriorities(modules);
//call the base sort since it resolves dependencies, then re-sort
var result = new List<ModuleInfo>(base.Sort(modules));
result.Sort((x, y) =>
{
string xModuleName = x.ModuleName;
string yModuleName = y.ModuleName;
//if one depends on other then non-dependent must come first
//otherwise base on priority
if (x.DependsOn.Contains(yModuleName))
return 1; //x after y
else if (y.DependsOn.Contains(xModuleName))
return -1; //y after x
else
return priorities[xModuleName].CompareTo(priorities[yModuleName]);
});
return result;
}
}
/// <summary>Where are the modules located</summary>
/// <returns></returns>
protected override IModuleCatalog GetModuleCatalog()
{
return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
class Bootstrapper : UnityBootstrapper
{
protected override System.Windows.DependencyObject CreateShell() {...}
protected override void InitializeShell() {...}
protected override IModuleCatalog CreateModuleCatalog()
{
return new AggregateModuleCatalog();
}
protected override void ConfigureModuleCatalog()
{
((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Services" });
((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Views" });
}
}
public class AggregateModuleCatalog : IModuleCatalog
{
private List<IModuleCatalog> catalogs = new List<IModuleCatalog>();
/// <summary>
/// Initializes a new instance of the <see cref="AggregateModuleCatalog"/> class.
/// </summary>
public AggregateModuleCatalog()
{
this.catalogs.Add(new ModuleCatalog());
}
/// <summary>
/// Gets the collection of catalogs.
/// </summary>
/// <value>A read-only collection of catalogs.</value>
public ReadOnlyCollection<IModuleCatalog> Catalogs
{
get
{
return this.catalogs.AsReadOnly();
}
}
/// <summary>
/// Adds the catalog to the list of catalogs
/// </summary>
/// <param name="catalog">The catalog to add.</param>
public void AddCatalog(IModuleCatalog catalog)
{
if (catalog == null)
{
throw new ArgumentNullException("catalog");
}
this.catalogs.Add(catalog);
}
/// <summary>
/// Gets all the <see cref="ModuleInfo"/> classes that are in the <see cref="ModuleCatalog"/>.
/// </summary>
/// <value></value>
public IEnumerable<ModuleInfo> Modules
{
get
{
return this.Catalogs.SelectMany(x => x.Modules);
}
}
/// <summary>
/// Return the list of <see cref="ModuleInfo"/>s that <paramref name="moduleInfo"/> depends on.
/// </summary>
/// <param name="moduleInfo">The <see cref="ModuleInfo"/> to get the</param>
/// <returns>
/// An enumeration of <see cref="ModuleInfo"/> that <paramref name="moduleInfo"/> depends on.
/// </returns>
public IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)
{
var catalog = this.catalogs.Single(x => x.Modules.Contains(moduleInfo));
return catalog.GetDependentModules(moduleInfo);
}
/// <summary>
/// Returns the collection of <see cref="ModuleInfo"/>s that contain both the <see cref="ModuleInfo"/>s in
/// <paramref name="modules"/>, but also all the modules they depend on.
/// </summary>
/// <param name="modules">The modules to get the dependencies for.</param>
/// <returns>
/// A collection of <see cref="ModuleInfo"/> that contains both all <see cref="ModuleInfo"/>s in <paramref name="modules"/>
/// and also all the <see cref="ModuleInfo"/> they depend on.
/// </returns>
public IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
{
var modulesGroupedByCatalog = modules.GroupBy<ModuleInfo, IModuleCatalog>(module => this.catalogs.Single(catalog => catalog.Modules.Contains(module)));
return modulesGroupedByCatalog.SelectMany(x => x.Key.CompleteListWithDependencies(x));
}
/// <summary>
/// Initializes the catalog, which may load and validate the modules.
/// </summary>
public void Initialize()
{
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
}
}
/// <summary>
/// Adds a <see cref="ModuleInfo"/> to the <see cref="ModuleCatalog"/>.
/// </summary>
/// <param name="moduleInfo">The <see cref="ModuleInfo"/> to add.</param>
public void AddModule(ModuleInfo moduleInfo)
{
this.catalogs[0].AddModule(moduleInfo);
}
}