diff --git a/src/Orchard.Tests/Environment/DefaultCompositionStrategyTests.cs b/src/Orchard.Tests/Environment/DefaultCompositionStrategyTests.cs index a44902b5d..d207155eb 100644 --- a/src/Orchard.Tests/Environment/DefaultCompositionStrategyTests.cs +++ b/src/Orchard.Tests/Environment/DefaultCompositionStrategyTests.cs @@ -7,6 +7,7 @@ using Autofac; using Autofac.Core; using Moq; using NUnit.Framework; +using Orchard.ContentManagement; using Orchard.ContentManagement.Records; using Orchard.Environment; using Orchard.Environment.Configuration; @@ -294,5 +295,32 @@ namespace Orchard.Tests.Environment { Assert.That(bar.TableName, Is.EqualTo("Yadda_Bar_BarRecord")); } + [Test] + public void FeatureReplacement() { + var descriptor = Build.ShellDescriptor().WithFeatures("Bar"); + + _extensionDescriptors = new[] { + Build.ExtensionDescriptor("Foo").WithFeatures("Bar"), + }; + + _featureTypes["Bar"] = new[] { typeof(ReplacedStubType), typeof(StubType), typeof(ReplacedStubNestedType), typeof(StubNestedType) }; + + var compositionStrategy = _container.Resolve(); + var blueprint = compositionStrategy.Compose(BuildDefaultSettings(), descriptor); + + Assert.That(blueprint.Dependencies.Count(), Is.EqualTo(2)); + Assert.That(blueprint.Dependencies.FirstOrDefault(dependency => dependency.Type.Equals(typeof(StubType))), Is.Not.Null); + Assert.That(blueprint.Dependencies.FirstOrDefault(dependency => dependency.Type.Equals(typeof(StubNestedType))), Is.Not.Null); + } + + [OrchardDependencyReplace("Orchard.Tests.Environment.DefaultCompositionStrategyTests+ReplacedStubNestedType")] + internal class StubNestedType : IDependency {} + + internal class ReplacedStubNestedType : IDependency {} } + + [OrchardDependencyReplace("Orchard.Tests.Environment.ReplacedStubType")] + internal class StubType : IDependency { } + + internal class ReplacedStubType : IDependency { } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/OrchardDependencyReplaceAttribute.cs b/src/Orchard/Environment/Extensions/OrchardDependencyReplaceAttribute.cs new file mode 100644 index 000000000..7b0a19b74 --- /dev/null +++ b/src/Orchard/Environment/Extensions/OrchardDependencyReplaceAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Orchard.Environment.Extensions { + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class OrchardDependencyReplaceAttribute : Attribute { + public OrchardDependencyReplaceAttribute(string dependency) { + Dependency = dependency; + } + + public string Dependency { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs index 288bcfad6..4e64d0727 100644 --- a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs +++ b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs @@ -72,9 +72,22 @@ namespace Orchard.Environment.ShellBuilders { IEnumerable features, Func predicate, Func selector) { + HashSet excludedTypes = new HashSet(); + + // Identify replaced types + foreach(Feature feature in features) { + foreach (Type type in feature.ExportedTypes) { + foreach (OrchardDependencyReplaceAttribute replacedType in type.GetCustomAttributes(typeof(OrchardDependencyReplaceAttribute), false)) { + excludedTypes.Add(replacedType.Dependency); + } + } + } + + // Load types excluding the replaced types return features.SelectMany( feature => feature.ExportedTypes .Where(predicate) + .Where(type => !excludedTypes.Contains(type.FullName)) .Select(type => selector(type, feature))) .ToArray(); }