/// <summary> /// Initializes a new instance of the <see cref="IxHost"/> class. /// This is first build phase. Second phase performed by <see cref="Initialize"/>. /// </summary> public IxHost() { _argumentProvider = new IxArgumentProvider(this); // TODO: Load priorities from configs. InstanceFactoryBuilder.Add(ExistingInstanceRawFactoryBuilder, 100); InstanceFactoryBuilder.Add(ClassInstanceFactoryBuilder, 200); InstanceFactoryBuilder.Add(DelegateInstanceBuilder, 300); VisibilityFilterBuilder.Add(StdVisibilityFilterBuilder, 100); ProviderNodeBuilder.Add(StdProviderConfigDefaultsSetter, 100); ProviderNodeBuilder.Add(ScopeBuilder, 200); ProviderNodeBuilder.Add(SingletonProviderBuilder, 300); ProviderNodeBuilder.Add(PerResolveProviderBuilder, 400); ScopeBinderBuilder.Add(RegistrationScopeBinderBuilder, 100); DisposeHandlerBuilder.Add(DisposableDisposeHandlerBuilder, 100); DisposeHandlerBuilder.Add(AsyncDisposableDisposeHandlerBuilder, 200); ResolveHandler.Add(SelfResolveInterceptor, 80); ResolveHandler.Add(ResolverResolveInterceptor, 100); ResolveHandler.Add(DirectCycleResolveInterceptor, 150); ResolveHandler.Add(SelfToChildrenResolver, 200); ResolveHandler.Add(StdResolveInterceptor, 300); ResolveHandler.Add(ResolveContextResolveInterceptor, 400); }
/// <summary> /// Second initialization phase. /// </summary> /// <param name="config">Host configuration.</param> /// <returns>Async execution TPL task.</returns> public async Task Initialize(IIxHostConfig config) { var allConfigNodes = new HashSet <IIxProviderNodeConfig>(); config.Nodes.Add( new IxStdProviderConfig { Identifier = new IxIdentifier(typeof(IIxHost)), InstanceBuilder = new IxExistingInstanceFactoryConfig <IIxHost>(this), DisposeHandler = obj => TaskEx.CompletedTask }); Action <IIxProviderNodeConfig, IxProviderNode> buildNodeAction = null; buildNodeAction = (nodeConfig, parentNode) => { if (!allConfigNodes.Add(nodeConfig)) { throw new InvalidOperationException( "Configuration contains the same object multiple times. Currently it's not allowed to avoid visitor cycles."); } IxProviderNode node = ProviderNodeBuilder.Delegate(nodeConfig, parentNode); // parent node is null only for root scope. if (parentNode == null) { _rootScope = (IxScope)node; } foreach (IIxProviderNodeConfig childConfig in nodeConfig.Nodes) { buildNodeAction(childConfig, node); } }; buildNodeAction(config, null); Action <IxProviderNode> importRegistrationsFromChildren = null; importRegistrationsFromChildren = node => { foreach (IxProviderNode child in node.Nodes) { importRegistrationsFromChildren(child); // Applying export to parent filter // while Blocking from exporting resolve pathes with zero-length. foreach (KeyValuePair <IxIdentifier, IxResolvePath> kvp in child.VisibleNodes.Where( x => child.ExportToParentFilter(x.Key) && x.Value.Path.Any())) { if (node.VisibleNodes.ContainsKey(kvp.Key)) { throw new InvalidOperationException("Export to parent node conflict."); } node.VisibleNodes.Add(kvp.Key, kvp.Value.ReRoot(node)); } } }; importRegistrationsFromChildren(_rootScope); Action <IxProviderNode> exportRegistrationsToChildren = null; exportRegistrationsToChildren = node => { KeyValuePair <IxIdentifier, IxResolvePath>[] registrationsToExport = node.VisibleNodes.Where(x => node.ExportFilter(x.Key)).ToArray(); if (!registrationsToExport.Any()) { return; } foreach (IxProviderNode child in node.Nodes) { foreach (KeyValuePair <IxIdentifier, IxResolvePath> kvp in registrationsToExport.Where(x => child.ImportFilter(x.Key))) { IxResolvePath resolvePath; if (child.VisibleNodes.TryGetValue(kvp.Key, out resolvePath)) { // Skipping self to children. if (resolvePath.Path.Any()) { // Direct cycle resolution replacement. if (!resolvePath.Target.ParentReplacementNodes.ContainsKey(kvp.Key)) { resolvePath.Target.ParentReplacementNodes.Add(kvp.Key, kvp.Value); } } } else { child.VisibleNodes.Add(kvp.Key, kvp.Value); } } exportRegistrationsToChildren(child); } }; exportRegistrationsToChildren(_rootScope); _rootScopeInstance = _rootScope.GetRootInstance(); var resolveContext = new IxResolveContext(_rootScopeInstance, null, new Dictionary <IxIdentifier, object>()); using (IIxInstanceLock rootResolverLock = await Resolve( _rootScopeInstance, new IxIdentifier(typeof(IIxResolver)), resolveContext, null)) { var resolver = (IxResolver)rootResolverLock.Target.Object; Critical.CheckedAssert( resolver.ParentContext == null && resolver.ParentFrame == null, "After resolve finished, resolver should not be bound to any context."); Resolver = resolver; } }