Composition

Discovery

When a modular app loads it usually looks for the associated composition modules and does so by dynamic discovery. This process usually requires at least two definitions: what to look for and where to look for it. The what is defined by an interface ICompositionModulewhilst the where in .NET case is the list of assemblies available for the app. There may be certain rules or conventions as to what are the exact assemblies to be discovered and inspected for app components. The existing discovery aspect answers the where question:

    public class DiscoveryAspect : IAspect, IAssemblySourceProvider 
    { 
        private readonly CompositionOptions _compositionOptions; 
        private readonly Type _rootType;
        
        public DiscoveryAspect(CompositionOptions compositionOptions, Type rootType = null)
        {
            _compositionOptions = compositionOptions;
            _rootType = rootType;
        }

        public void Initialize()
        {
            _assemblies = GetAssemblies();
        }

        public string Id => "Discovery";

        public string[] Dependencies => new[] { "Platform" };

        private Assembly[] _assemblies;

        public IEnumerable<Assembly> Assemblies => _assemblies ?? (_assemblies = GetAssemblies());

        private Assembly[] GetAssemblies()
        {
            var assembliesResolver = new AssembliesResolver(
            new CustomAssemblySourceProvider(
                PlatformProvider.Current.GetAbsolutePath(_compositionOptions.RelativePath),
                _compositionOptions.Prefixes), _rootType);
            return ((IAssembliesReadOnlyResolver) assembliesResolver).GetAssemblies().ToArray();
        }
    }

Modularity(again)

After we answer the where question we are ready to inspect the list of assemblies and answer the what question to get the list of composition modules ready to be registered into the app dependency registrator:

public sealed class ModularityAspect : IAspect, ICompositionModulesProvider, IHaveErrors
    {
        private readonly IAssemblySourceProvider _assemblySourceProvider; 
        private readonly CompositionOptions _options;
        
        public ModularityAspect(
            IAssemblySourceProvider assemblySourceProvider, 
            CompositionOptions options)
        {
            _assemblySourceProvider = assemblySourceProvider;
            _options = options;
        }

        public IEnumerable<ICompositionModule> Modules { get; private set; } = new ICompositionModule[] { };

        public IEnumerable<Exception> Errors { get; private set; } = new Exception[] { };

        public string RelativePath => _options.RelativePath;
    
        public string[] Prefixes => _options.Prefixes;

        public void Initialize()
        {
            CompositionManager compositionManager = new CompositionManager();
            ModularityInfo modularityInfo = new ModularityInfo();
            try
            {
                compositionManager.Initialize(_assemblySourceProvider.Assemblies);
            }
            catch (AggregateAssemblyInspectionException ex)
            {
                modularityInfo.Errors = ex.InnerExceptions;
            }
            finally
            {
                modularityInfo.Modules = compositionManager.Modules == null
                ? new ICompositionModule[0]
                : compositionManager.Modules.ToArray();
            }
            
            Modules = modularityInfo.Modules;
            Errors = modularityInfo.Errors;
        }

        public string Id => "Modularity";

        public string[] Dependencies => new[] { "Platform", "Discovery" };
}

Last updated