private async Task EnsureInitializedAsync() { if (_isInitialized) { return; } await _semaphore.WaitAsync(); try { if (_isInitialized) { return; } var modules = _applicationContext.Application.Modules; var loadedExtensions = new ConcurrentDictionary <string, ExtensionEntry>(); // Load all extensions in parallel await modules.ForEachAsync((module) => { if (!module.ModuleInfo.Exists) { return(Task.CompletedTask); } var manifestInfo = new ManifestInfo(module.ModuleInfo); var extensionInfo = new ExtensionInfo(module.SubPath, manifestInfo, (mi, ei) => { return(_featuresProvider.GetFeatures(ei, mi)); }); var entry = new ExtensionEntry { ExtensionInfo = extensionInfo, Assembly = module.Assembly, ExportedTypes = module.Assembly.ExportedTypes }; loadedExtensions.TryAdd(module.Name, entry); return(Task.CompletedTask); }); var loadedFeatures = new Dictionary <string, FeatureEntry>(); // Get all valid types from any extension var allTypesByExtension = loadedExtensions.SelectMany(extension => extension.Value.ExportedTypes.Where(IsComponentType) .Select(type => new { ExtensionEntry = extension.Value, Type = type })).ToArray(); var typesByFeature = allTypesByExtension .GroupBy(typeByExtension => GetSourceFeatureNameForType( typeByExtension.Type, typeByExtension.ExtensionEntry.ExtensionInfo.Id)) .ToDictionary( group => group.Key, group => group.Select(typesByExtension => typesByExtension.Type).ToArray()); foreach (var loadedExtension in loadedExtensions) { var extension = loadedExtension.Value; foreach (var feature in extension.ExtensionInfo.Features) { // Features can have no types if (typesByFeature.TryGetValue(feature.Id, out var featureTypes)) { foreach (var type in featureTypes) { _typeFeatureProvider.TryAdd(type, feature); } } else { featureTypes = Array.Empty <Type>(); } loadedFeatures.Add(feature.Id, new FeatureEntry(feature, featureTypes)); } } ; // Feature infos and entries are ordered by priority and dependencies. _featureInfos = Order(loadedFeatures.Values.Select(f => f.FeatureInfo)); _features = _featureInfos.ToDictionary(f => f.Id, f => loadedFeatures[f.Id]); // Extensions are also ordered according to the weight of their first features. _extensionsInfos = _featureInfos.Where(f => f.Id == f.Extension.Features.First().Id) .Select(f => f.Extension); _extensions = _extensionsInfos.ToDictionary(e => e.Id, e => loadedExtensions[e.Id]); _isInitialized = true; } finally { _semaphore.Release(); } }
private void EnsureInitialized() { if (_isInitialized) { return; } lock (InitializationSyncLock) { if (_isInitialized) { return; } var moduleNames = _hostingEnvironment.GetApplication().ModuleNames; var loadedExtensions = new ConcurrentDictionary <string, ExtensionEntry>(); // Load all extensions in parallel Parallel.ForEach(moduleNames, new ParallelOptions { MaxDegreeOfParallelism = 8 }, (name) => { var module = _hostingEnvironment.GetModule(name); if (!module.ModuleInfo.Exists) { return; } var manifestInfo = new ManifestInfo(module.ModuleInfo); var extensionInfo = new ExtensionInfo(module.SubPath, manifestInfo, (mi, ei) => { return(_featuresProvider.GetFeatures(ei, mi)); }); var entry = new ExtensionEntry { ExtensionInfo = extensionInfo, Assembly = module.Assembly, ExportedTypes = module.Assembly.ExportedTypes }; loadedExtensions.TryAdd(module.Name, entry); }); var loadedFeatures = new Dictionary <string, FeatureEntry>(); // Get all valid types from any extension var allTypesByExtension = loadedExtensions.SelectMany(extension => extension.Value.ExportedTypes.Where(IsComponentType) .Select(type => new { ExtensionEntry = extension.Value, Type = type })).ToArray(); var typesByFeature = allTypesByExtension .GroupBy(typeByExtension => GetSourceFeatureNameForType( typeByExtension.Type, typeByExtension.ExtensionEntry.ExtensionInfo.Id)) .ToDictionary( group => group.Key, group => group.Select(typesByExtension => typesByExtension.Type).ToArray()); foreach (var loadedExtension in loadedExtensions) { var extension = loadedExtension.Value; foreach (var feature in extension.ExtensionInfo.Features) { // Features can have no types if (typesByFeature.TryGetValue(feature.Id, out var featureTypes)) { foreach (var type in featureTypes) { _typeFeatureProvider.TryAdd(type, feature); } } else { featureTypes = Array.Empty <Type>(); } loadedFeatures.Add(feature.Id, new CompiledFeatureEntry(feature, featureTypes)); } } ; // Feature infos and entries are ordered by priority and dependencies. _featureInfos = Order(loadedFeatures.Values.Select(f => f.FeatureInfo)); _features = _featureInfos.ToDictionary(f => f.Id, f => loadedFeatures[f.Id]); // Extensions are also ordered according to the weight of their first features. _extensionsInfos = _featureInfos.Where(f => f.Id == f.Extension.Features.First().Id) .Select(f => f.Extension); _extensions = _extensionsInfos.ToDictionary(e => e.Id, e => loadedExtensions[e.Id]); _isInitialized = true; } }