Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I didn't like the idea of using ModuleDependency because this would mean that module a would not load when module b was not present, when in fact there was no dependency. Instead I created a priority attribute to decorate the module:</p> <pre><code>/// &lt;summary&gt; /// Allows the order of module loading to be controlled. Where dependencies /// allow, module loading order will be controlled by relative values of priority /// &lt;/summary&gt; [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public sealed class PriorityAttribute : Attribute { /// &lt;summary&gt; /// Constructor /// &lt;/summary&gt; /// &lt;param name="priority"&gt;the priority to assign&lt;/param&gt; public PriorityAttribute(int priority) { this.Priority = priority; } /// &lt;summary&gt; /// Gets or sets the priority of the module. /// &lt;/summary&gt; /// &lt;value&gt;The priority of the module.&lt;/value&gt; public int Priority { get; private set; } } </code></pre> <p>I then decorated the modules like this:</p> <pre><code>[Priority(200)] [Module(ModuleName = "MyModule")] public class MyModule : IModule </code></pre> <p>I created a new descendent of DirectoryModuleCatalog:</p> <pre><code>/// &lt;summary&gt; /// ModuleCatalog that respects PriorityAttribute for sorting modules /// &lt;/summary&gt; [SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)] public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog { /// &lt;summary&gt; /// local class to load assemblies into different appdomain which is then discarded /// &lt;/summary&gt; private class ModulePriorityLoader : MarshalByRefObject { /// &lt;summary&gt; /// Get the priorities /// &lt;/summary&gt; /// &lt;param name="modules"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")] public Dictionary&lt;string, int&gt; GetPriorities(IEnumerable&lt;ModuleInfo&gt; 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&lt;string, int&gt;(); var assemblies = new Dictionary&lt;string, Assembly&gt;(); 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 =&gt; t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal)) .First(); var priorityAttribute = CustomAttributeData.GetCustomAttributes(type).FirstOrDefault( cad =&gt; 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; } } /// &lt;summary&gt; /// 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 /// &lt;/summary&gt; /// &lt;param name="modules"&gt;modules to retrieve priorities for&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; private Dictionary&lt;string, int&gt; GetModulePriorities(IEnumerable&lt;ModuleInfo&gt; 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); } } /// &lt;summary&gt; /// Sort modules according to dependencies and Priority /// &lt;/summary&gt; /// &lt;param name="modules"&gt;modules to sort&lt;/param&gt; /// &lt;returns&gt;sorted modules&lt;/returns&gt; protected override IEnumerable&lt;ModuleInfo&gt; Sort(IEnumerable&lt;ModuleInfo&gt; modules) { Dictionary&lt;string, int&gt; priorities = GetModulePriorities(modules); //call the base sort since it resolves dependencies, then re-sort var result = new List&lt;ModuleInfo&gt;(base.Sort(modules)); result.Sort((x, y) =&gt; { 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; } } </code></pre> <p>Finally, I changed the bootstrapper to use this new catalog:</p> <pre><code> /// &lt;summary&gt;Where are the modules located&lt;/summary&gt; /// &lt;returns&gt;&lt;/returns&gt; protected override IModuleCatalog GetModuleCatalog() { return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" }; } </code></pre> <p>I'm not sure if the stuff with assembly loading is the best way to do things, but it seems to work...</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload