From ae2a157b526129dcce547121d17f5e92e4f2f278 Mon Sep 17 00:00:00 2001 From: loudej Date: Tue, 1 Dec 2009 21:29:16 +0000 Subject: [PATCH] Adding an IPackageLoader abstraction to extract assembly mechanics from IPackageManager --HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4042859 --- ...rdControllerIdentificationStrategyTests.cs | 3 +- .../Packages/PackageManagerTests.cs | 3 + .../Environment/DefaultCompositionStrategy.cs | 2 +- src/Orchard/Environment/OrchardStarter.cs | 8 ++- src/Orchard/Mvc/MvcModule.cs | 15 +++-- ...OrchardControllerIdentificationStrategy.cs | 12 ++++ src/Orchard/Orchard.csproj | 5 ++ .../Packages/Loaders/CorePackageLoader.cs | 28 +++++++++ .../Packages/Loaders/DynamicPackageLoader.cs | 58 +++++++++++++++++++ .../Packages/Loaders/IPackageLoader.cs | 6 ++ .../Loaders/PrecompiledPackageLoader.cs | 21 +++++++ .../Loaders/ReferencedPackageLoader.cs | 31 ++++++++++ src/Orchard/Packages/PackageManager.cs | 39 ++++++------- 13 files changed, 201 insertions(+), 30 deletions(-) create mode 100644 src/Orchard/Packages/Loaders/CorePackageLoader.cs create mode 100644 src/Orchard/Packages/Loaders/DynamicPackageLoader.cs create mode 100644 src/Orchard/Packages/Loaders/IPackageLoader.cs create mode 100644 src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs create mode 100644 src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs diff --git a/src/Orchard.Tests/Mvc/OrchardControllerIdentificationStrategyTests.cs b/src/Orchard.Tests/Mvc/OrchardControllerIdentificationStrategyTests.cs index 63a0af9c8..f71202766 100644 --- a/src/Orchard.Tests/Mvc/OrchardControllerIdentificationStrategyTests.cs +++ b/src/Orchard.Tests/Mvc/OrchardControllerIdentificationStrategyTests.cs @@ -6,12 +6,13 @@ using System.Web.Mvc; using Autofac; using NUnit.Framework; using Orchard.Mvc; +using Orchard.Packages; namespace Orchard.Tests.Mvc { [TestFixture] public class OrchardControllerIdentificationStrategyTests { [Test] public void IdentificationStrategyAddsAssemblyNameAsAreaPrefixToControllerNames() { - var strategy = new OrchardControllerIdentificationStrategy(); + var strategy = new OrchardControllerIdentificationStrategy(Enumerable.Empty()); var service = strategy.ServiceForControllerType(typeof (StrategyTestingController)); Assert.That(service, Is.TypeOf()); Assert.That(((NamedService)service).ServiceName, Is.EqualTo("controller.orchard.tests.strategytesting")); diff --git a/src/Orchard.Tests/Packages/PackageManagerTests.cs b/src/Orchard.Tests/Packages/PackageManagerTests.cs index dd571374d..f97f1aaf5 100644 --- a/src/Orchard.Tests/Packages/PackageManagerTests.cs +++ b/src/Orchard.Tests/Packages/PackageManagerTests.cs @@ -5,8 +5,10 @@ using System.Linq; using System.Text; using Autofac; using Autofac.Builder; +using Autofac.Modules; using NUnit.Framework; using Orchard.Packages; +using Orchard.Packages.Loaders; using Yaml.Grammar; namespace Orchard.Tests.Packages { @@ -20,6 +22,7 @@ namespace Orchard.Tests.Packages { public void Init() { var builder = new ContainerBuilder(); _folders = new StubFolders(); + builder.RegisterModule(new ImplicitCollectionSupportModule()); builder.Register(_folders).As(); builder.Register().As(); _container = builder.Build(); diff --git a/src/Orchard/Environment/DefaultCompositionStrategy.cs b/src/Orchard/Environment/DefaultCompositionStrategy.cs index fceefcb40..92880674d 100644 --- a/src/Orchard/Environment/DefaultCompositionStrategy.cs +++ b/src/Orchard/Environment/DefaultCompositionStrategy.cs @@ -58,7 +58,7 @@ namespace Orchard.Environment { private static bool IsRecordType(Type type) { - return (type.Namespace.EndsWith(".Models") || type.Namespace.EndsWith(".Records")) && + return ((type.Namespace ?? "").EndsWith(".Models") || (type.Namespace ?? "").EndsWith(".Records")) && type.GetProperty("Id") != null && (type.GetProperty("Id").GetAccessors() ?? Enumerable.Empty()).All(x => x.IsVirtual) && !type.IsSealed && diff --git a/src/Orchard/Environment/OrchardStarter.cs b/src/Orchard/Environment/OrchardStarter.cs index 3cb151eff..e9bc61237 100644 --- a/src/Orchard/Environment/OrchardStarter.cs +++ b/src/Orchard/Environment/OrchardStarter.cs @@ -7,6 +7,7 @@ using Autofac.Builder; using Autofac.Integration.Web; using Autofac.Modules; using Orchard.Packages; +using Orchard.Packages.Loaders; namespace Orchard.Environment { public static class OrchardStarter { @@ -29,8 +30,11 @@ namespace Orchard.Environment { // still needs to be called on end request, but that's the host component's job to worry about. builder.Register().As().ContainerScoped(); - builder.Register().As() - .SingletonScoped(); + builder.Register().As().SingletonScoped(); + builder.Register().As().SingletonScoped(); + builder.Register().As().SingletonScoped(); + builder.Register().As().SingletonScoped(); + builder.Register().As().SingletonScoped(); //builder.Register((ctx, p) => new PackageFolders(MapPaths(p.Named>("paths")))) // .As() diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 050705e01..5ea17dd07 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -2,28 +2,33 @@ using System.Web; using Autofac.Builder; using Autofac.Integration.Web.Mvc; +using Orchard.Controllers; using Orchard.Environment; using Orchard.Mvc.Filters; +using Orchard.Packages; namespace Orchard.Mvc { public class MvcModule : Module { private readonly ICompositionStrategy _compositionStrategy; + private readonly IPackageManager _packageManager; - public MvcModule(ICompositionStrategy compositionStrategy) { + public MvcModule(ICompositionStrategy compositionStrategy, IPackageManager packageManager) { _compositionStrategy = compositionStrategy; + _packageManager = packageManager; } protected override void Load(ContainerBuilder moduleBuilder) { - var assemblies = _compositionStrategy.GetAssemblies().ToArray(); + var packages = _packageManager.ActivePackages(); + var assemblies = packages.Select(x => x.Assembly).Concat(new[] { typeof(HomeController).Assembly }); - var module = new AutofacControllerModule(assemblies) { + var module = new AutofacControllerModule(assemblies.ToArray()) { ActionInvokerType = typeof(FilterResolvingActionInvoker), - IdentificationStrategy = new OrchardControllerIdentificationStrategy() + IdentificationStrategy = new OrchardControllerIdentificationStrategy(packages) }; moduleBuilder.RegisterModule(module); moduleBuilder - .Register(ctx => HttpContext.Current ==null ? null : new HttpContextWrapper(HttpContext.Current)) + .Register(ctx => HttpContext.Current == null ? null : new HttpContextWrapper(HttpContext.Current)) .As() .FactoryScoped(); } diff --git a/src/Orchard/Mvc/OrchardControllerIdentificationStrategy.cs b/src/Orchard/Mvc/OrchardControllerIdentificationStrategy.cs index 594fd4857..1f80e32ad 100644 --- a/src/Orchard/Mvc/OrchardControllerIdentificationStrategy.cs +++ b/src/Orchard/Mvc/OrchardControllerIdentificationStrategy.cs @@ -1,10 +1,18 @@ using System; +using System.Collections.Generic; using System.Linq; using Autofac; using Autofac.Integration.Web.Mvc; +using Orchard.Packages; namespace Orchard.Mvc { public class OrchardControllerIdentificationStrategy : IControllerIdentificationStrategy { + private readonly IEnumerable _packages; + + public OrchardControllerIdentificationStrategy(IEnumerable packages) { + _packages = packages; + } + public Service ServiceForControllerName(string controllerName) { // the OrchardControllerFactory class does not call on the strategy, because the controller name // alone is insufficient to identify the service @@ -13,6 +21,7 @@ namespace Orchard.Mvc { public Service ServiceForControllerType(Type controllerType) { var controllerNamespace = controllerType.Namespace; + var package = _packages.FirstOrDefault(x => x.Assembly == controllerType.Assembly); var assemblySimpleName = controllerType.Assembly.GetName().Name; string areaName; if (assemblySimpleName == "Orchard.Core" && @@ -20,6 +29,9 @@ namespace Orchard.Mvc { areaName = controllerNamespace.Split('.').Skip(2).FirstOrDefault(); } + else if (package != null) { + areaName = package.Descriptor.Name; + } else { areaName = assemblySimpleName; } diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj index e0b1dfaf5..34d613c5e 100644 --- a/src/Orchard/Orchard.csproj +++ b/src/Orchard/Orchard.csproj @@ -189,6 +189,11 @@ ASPXCodeBehind + + + + + diff --git a/src/Orchard/Packages/Loaders/CorePackageLoader.cs b/src/Orchard/Packages/Loaders/CorePackageLoader.cs new file mode 100644 index 000000000..f1d90ab68 --- /dev/null +++ b/src/Orchard/Packages/Loaders/CorePackageLoader.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Orchard.Packages.Loaders { + public class CorePackageLoader : IPackageLoader { + public int Order { get { return 1; } } + + public PackageEntry Load(PackageDescriptor descriptor) { + if (descriptor.Location == "~/Core") { + + var assembly = Assembly.Load("Orchard.Core"); + return new PackageEntry { + Descriptor = descriptor, + Assembly = assembly, + ExportedTypes = assembly.GetExportedTypes().Where(x => IsTypeFromPackage(x, descriptor)) + }; + } + return null; + } + + private static bool IsTypeFromPackage(Type type, PackageDescriptor descriptor) { + return (type.Namespace + ".").StartsWith("Orchard.Core." + descriptor.Name + "."); + } + } +} diff --git a/src/Orchard/Packages/Loaders/DynamicPackageLoader.cs b/src/Orchard/Packages/Loaders/DynamicPackageLoader.cs new file mode 100644 index 000000000..1fce504f3 --- /dev/null +++ b/src/Orchard/Packages/Loaders/DynamicPackageLoader.cs @@ -0,0 +1,58 @@ +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Web.Compilation; +using System.Web.Hosting; + +namespace Orchard.Packages.Loaders { + public class DynamicPackageLoader : IPackageLoader { + public int Order { get { return 4; } } + + public PackageEntry Load(PackageDescriptor descriptor) { + if (HostingEnvironment.IsHosted == false) + return null; + + var codeProvider = CodeDomProvider.CreateProvider("cs"); + + var references = GetAssemblyReferenceNames(); + var options = new CompilerParameters(references.ToArray()); + + var locationPath = HostingEnvironment.MapPath(descriptor.Location); + var packagePath = Path.Combine(locationPath, descriptor.Name); + + var fileNames = GetSourceFileNames(packagePath); + var results = codeProvider.CompileAssemblyFromFile(options, fileNames.ToArray()); + + return new PackageEntry { + Descriptor = descriptor, + Assembly = results.CompiledAssembly, + ExportedTypes = results.CompiledAssembly.GetExportedTypes(), + }; + } + + private IEnumerable GetAssemblyReferenceNames() { + return BuildManager.GetReferencedAssemblies() + .OfType() + .Select(x => x.Location) + .Where(x => !string.IsNullOrEmpty(x)) + .Distinct(); + } + + private IEnumerable GetSourceFileNames(string path) { + foreach(var file in Directory.GetFiles(path, "*.cs")) { + yield return file; + } + + foreach(var folder in Directory.GetDirectories(path)) { + if (Path.GetFileName(folder).StartsWith(".")) + continue; + + foreach(var file in GetSourceFileNames(folder)) { + yield return file; + } + } + } + } +} diff --git a/src/Orchard/Packages/Loaders/IPackageLoader.cs b/src/Orchard/Packages/Loaders/IPackageLoader.cs new file mode 100644 index 000000000..bbb200c2a --- /dev/null +++ b/src/Orchard/Packages/Loaders/IPackageLoader.cs @@ -0,0 +1,6 @@ +namespace Orchard.Packages.Loaders { + public interface IPackageLoader { + int Order { get; } + PackageEntry Load(PackageDescriptor descriptor); + } +} \ No newline at end of file diff --git a/src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs b/src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs new file mode 100644 index 000000000..2d478f52a --- /dev/null +++ b/src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Orchard.Packages.Loaders { + public class PrecompiledPackageLoader : IPackageLoader { + public int Order { get { return 3; } } + + public PackageEntry Load(PackageDescriptor descriptor) { + //var assembly = Assembly.Load(descriptor.Name); + //return new PackageEntry { + // Descriptor = descriptor, + // Assembly = assembly, + // ExportedTypes = assembly.GetExportedTypes() + //}; + return null; + } + } +} diff --git a/src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs b/src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs new file mode 100644 index 000000000..7d8a5944c --- /dev/null +++ b/src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Web.Compilation; +using System.Web.Hosting; + +namespace Orchard.Packages.Loaders { + public class ReferencedPackageLoader : IPackageLoader { + public int Order { get { return 2; } } + + public PackageEntry Load(PackageDescriptor descriptor) { + if (HostingEnvironment.IsHosted == false) + return null; + + var assembly = BuildManager.GetReferencedAssemblies() + .OfType() + .FirstOrDefault(x=>x.GetName().Name == descriptor.Name); + + if (assembly == null) + return null; + + return new PackageEntry { + Descriptor = descriptor, + Assembly = assembly, + ExportedTypes = assembly.GetExportedTypes() + }; + } + } +} diff --git a/src/Orchard/Packages/PackageManager.cs b/src/Orchard/Packages/PackageManager.cs index b259d5ac2..56a6a9c2e 100644 --- a/src/Orchard/Packages/PackageManager.cs +++ b/src/Orchard/Packages/PackageManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using Orchard.Packages.Loaders; using Yaml.Grammar; namespace Orchard.Packages { @@ -13,9 +14,12 @@ namespace Orchard.Packages { public class PackageManager : IPackageManager { private readonly IPackageFolders _folders; + private readonly IEnumerable _loaders; + private IEnumerable _activePackages; - public PackageManager(IPackageFolders folders) { + public PackageManager(IPackageFolders folders, IEnumerable loaders) { _folders = folders; + _loaders = loaders.OrderBy(x => x.Order); } @@ -48,35 +52,28 @@ namespace Orchard.Packages { } public IEnumerable ActivePackages() { + if (_activePackages == null) { + _activePackages = BuildActivePackages().ToList(); + } + return _activePackages; + } + + private IEnumerable BuildActivePackages() { foreach (var descriptor in AvailablePackages()) { //TODO: this component needs access to some "current settings" to know which are active yield return BuildEntry(descriptor); } } - private static PackageEntry BuildEntry(PackageDescriptor descriptor) { - if (descriptor.Location == "~/Core") { - - var assembly = Assembly.Load("Orchard.Core"); - return new PackageEntry { - Descriptor = descriptor, - Assembly = assembly, - ExportedTypes = assembly.GetExportedTypes().Where(x => IsTypeFromPackage(x, descriptor)) - }; - } - else { - var assembly = Assembly.Load(descriptor.Name); - return new PackageEntry { - Descriptor = descriptor, - Assembly = assembly, - ExportedTypes = assembly.GetExportedTypes() - }; + private PackageEntry BuildEntry(PackageDescriptor descriptor) { + foreach (var loader in _loaders) { + var entry = loader.Load(descriptor); + if (entry != null) + return entry; } + return null; } - private static bool IsTypeFromPackage(Type type, PackageDescriptor descriptor) { - return (type.Namespace + ".").StartsWith("Orchard.Core." + descriptor.Name + "."); - } } }