diff --git a/src/OrchardCore/OrchardCore.Abstractions/Extensions/IExtensionManager.cs b/src/OrchardCore/OrchardCore.Abstractions/Extensions/IExtensionManager.cs index 11854790320..c34fb79ef04 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Extensions/IExtensionManager.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Extensions/IExtensionManager.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Threading.Tasks; using OrchardCore.Environment.Extensions.Features; @@ -9,7 +8,6 @@ public interface IExtensionManager { IExtensionInfo GetExtension(string extensionId); IEnumerable GetExtensions(); - IEnumerable GetExportedExtensionTypes(IExtensionInfo extensionInfo); Task LoadExtensionAsync(IExtensionInfo extensionInfo); IEnumerable GetFeatures(); diff --git a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs index d942df73b7c..e0dce6993a7 100644 --- a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs +++ b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs @@ -3,7 +3,7 @@ using System.Collections.Frozen; using System.Collections.Generic; using System.Linq; -using System.Threading; +using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using OrchardCore.Environment.Extensions.Features; @@ -24,6 +24,7 @@ public class ExtensionManager : IExtensionManager private readonly IExtensionDependencyStrategy[] _extensionDependencyStrategies; private readonly IExtensionPriorityStrategy[] _extensionPriorityStrategies; + private readonly ITypeFeatureProvider _typeFeatureProvider; private readonly IFeaturesProvider _featuresProvider; private FrozenDictionary _extensions; @@ -41,12 +42,14 @@ public ExtensionManager( IApplicationContext applicationContext, IEnumerable extensionDependencyStrategies, IEnumerable extensionPriorityStrategies, + ITypeFeatureProvider typeFeatureProvider, IFeaturesProvider featuresProvider, ILogger logger) { _applicationContext = applicationContext; _extensionDependencyStrategies = extensionDependencyStrategies as IExtensionDependencyStrategy[] ?? extensionDependencyStrategies.ToArray(); _extensionPriorityStrategies = extensionPriorityStrategies as IExtensionPriorityStrategy[] ?? extensionPriorityStrategies.ToArray(); + _typeFeatureProvider = typeFeatureProvider; _featuresProvider = featuresProvider; L = logger; } @@ -89,18 +92,6 @@ public IEnumerable GetFeatures(string[] featureIdsToLoad) } } - public IEnumerable GetExportedExtensionTypes(IExtensionInfo extensionInfo) - { - EnsureInitialized(); - - if (_extensions.TryGetValue(extensionInfo.Id, out var extension)) - { - return extension.ExportedTypes; - } - - return []; - } - public Task LoadExtensionAsync(IExtensionInfo extensionInfo) { EnsureInitialized(); @@ -113,7 +104,7 @@ public Task LoadExtensionAsync(IExtensionInfo extensionInfo) public Task> LoadFeaturesAsync() { EnsureInitialized(); - + return Task.FromResult>(_features.Values); } @@ -309,12 +300,49 @@ private void EnsureInitialized() var loadedFeatures = new Dictionary(); + // Get all types from all extension and add them to the type feature provider. + var allTypesByExtension = loadedExtensions + .SelectMany(extension => + extension + .Value + .ExportedTypes + .Where(IsComponentType) + .Select(type => new + { + Extension = extension.Value, + Type = type + })); + + var typesByFeature = allTypesByExtension + .GroupBy(typeByExtension => GetSourceFeatureNameForType( + typeByExtension.Type, + typeByExtension.Extension.ExtensionInfo.Id)) + .ToDictionary( + group => group.Key, + group => group.Select(typesByExtension => typesByExtension.Type)); + 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)) + { + // This is adding the types to the main feature for backward compatibility. + // In the future we could stop doing it as we don't expect this to be necessary, and remove the FeatureTypeDiscovery attribute. + foreach (var type in featureTypes) + { + // If the attribute is present then we explicitly ignore the backward compatibility and skip the registration + // in the main feature. + if (!SkipExtensionFeatureRegistration(type)) + { + _typeFeatureProvider.TryAdd(type, feature); + } + } + } + loadedFeatures.Add(feature.Id, feature); } } @@ -366,5 +394,22 @@ private int GetPriority(IFeatureInfo feature) return sum; } + + private static string GetSourceFeatureNameForType(Type type, string extensionId) + { + var attribute = type.GetCustomAttributes(false).FirstOrDefault(); + + return attribute?.FeatureName ?? extensionId; + } + + private static bool IsComponentType(Type type) + { + return type.IsClass && !type.IsAbstract && type.IsPublic; + } + + private static bool SkipExtensionFeatureRegistration(Type type) + { + return FeatureTypeDiscoveryAttribute.GetFeatureTypeDiscoveryForType(type)?.SkipExtension ?? false; + } } } diff --git a/src/OrchardCore/OrchardCore/Shell/Builders/ShellContainerFactory.cs b/src/OrchardCore/OrchardCore/Shell/Builders/ShellContainerFactory.cs index 348c3d013c3..ce30f98decd 100644 --- a/src/OrchardCore/OrchardCore/Shell/Builders/ShellContainerFactory.cs +++ b/src/OrchardCore/OrchardCore/Shell/Builders/ShellContainerFactory.cs @@ -152,49 +152,6 @@ private void EnsureApplicationFeature() private void PopulateTypeFeatureProvider(ITypeFeatureProvider typeFeatureProvider, FeatureAwareServiceCollection featureAwareServiceCollection) { - // Get all types from all extension and add them to the type feature provider. - var extensions = _extensionManager.GetExtensions(); - - var allTypesByExtension = extensions - .SelectMany(extension => - _extensionManager.GetExportedExtensionTypes(extension) - .Where(IsComponentType) - .Select(type => new - { - Extension = extension, - Type = type - })); - - var typesByFeature = allTypesByExtension - .GroupBy(typeByExtension => GetSourceFeatureNameForType( - typeByExtension.Type, - typeByExtension.Extension.Id)) - .ToDictionary( - group => group.Key, - group => group.Select(typesByExtension => typesByExtension.Type)); - - foreach (var extension in extensions) - { - foreach (var feature in extension.Features) - { - // Features can have no types. - if (typesByFeature.TryGetValue(feature.Id, out var featureTypes)) - { - // This is adding the types to the main feature for backward compatibility. - // In the future we could stop doing it as we don't expect this to be necessary, and remove the FeatureTypeDiscovery attribute. - foreach (var type in featureTypes) - { - // If the attribute is present then we explicitly ignore the backward compatibility and skip the registration - // in the main feature. - if (!SkipExtensionFeatureRegistration(type)) - { - typeFeatureProvider.TryAdd(type, feature); - } - } - } - } - } - // Register all DIed types in ITypeFeatureProvider. foreach (var featureServiceCollection in featureAwareServiceCollection.FeatureCollections) { @@ -223,22 +180,5 @@ private void PopulateTypeFeatureProvider(ITypeFeatureProvider typeFeatureProvide } } } - - private static string GetSourceFeatureNameForType(Type type, string extensionId) - { - var attribute = type.GetCustomAttributes(false).FirstOrDefault(); - - return attribute?.FeatureName ?? extensionId; - } - - private static bool IsComponentType(Type type) - { - return type.IsClass && !type.IsAbstract && type.IsPublic; - } - - private static bool SkipExtensionFeatureRegistration(Type type) - { - return FeatureTypeDiscoveryAttribute.GetFeatureTypeDiscoveryForType(type)?.SkipExtension ?? false; - } } } diff --git a/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs b/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs index 40e0806515f..ff971ff35cc 100644 --- a/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs @@ -276,11 +276,6 @@ public Task> LoadFeaturesAsync(string[] featureIdsToLo { throw new NotImplementedException(); } - - public IEnumerable GetExportedExtensionTypes(IExtensionInfo extensionInfo) - { - throw new NotImplementedException(); - } } public class TestShapeProvider : IShapeTableProvider diff --git a/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs b/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs index 47b5711f518..1ae8e2bfd45 100644 --- a/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs +++ b/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs @@ -31,6 +31,7 @@ public ExtensionManagerTests() _applicationContext, new[] { new ExtensionDependencyStrategy() }, new[] { new ExtensionPriorityStrategy() }, + new TypeFeatureProvider(), _moduleFeatureProvider, new NullLogger() ); @@ -39,6 +40,7 @@ public ExtensionManagerTests() _applicationContext, new[] { new ExtensionDependencyStrategy() }, new[] { new ExtensionPriorityStrategy() }, + new TypeFeatureProvider(), _themeFeatureProvider, new NullLogger() ); @@ -47,6 +49,7 @@ public ExtensionManagerTests() _applicationContext, new IExtensionDependencyStrategy[] { new ExtensionDependencyStrategy(), new ThemeExtensionDependencyStrategy() }, new[] { new ExtensionPriorityStrategy() }, + new TypeFeatureProvider(), _themeFeatureProvider, new NullLogger() ); diff --git a/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs b/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs index 2b81df56ef3..bfc0c988776 100644 --- a/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs +++ b/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs @@ -10,11 +10,6 @@ public IEnumerable GetDependentFeatures(string featureId) throw new NotImplementedException(); } - public IEnumerable GetExportedExtensionTypes(IExtensionInfo extensionInfo) - { - throw new NotImplementedException(); - } - public IExtensionInfo GetExtension(string extensionId) { throw new NotImplementedException();