mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-18 17:47:54 +08:00
Adding an IPackageLoader abstraction to extract assembly mechanics from IPackageManager
--HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4042859
This commit is contained in:
@@ -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<PackageEntry>());
|
||||
var service = strategy.ServiceForControllerType(typeof (StrategyTestingController));
|
||||
Assert.That(service, Is.TypeOf<NamedService>());
|
||||
Assert.That(((NamedService)service).ServiceName, Is.EqualTo("controller.orchard.tests.strategytesting"));
|
||||
|
@@ -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<IPackageFolders>();
|
||||
builder.Register<PackageManager>().As<IPackageManager>();
|
||||
_container = builder.Build();
|
||||
|
@@ -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<MethodInfo>()).All(x => x.IsVirtual) &&
|
||||
!type.IsSealed &&
|
||||
|
@@ -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<ContainerProvider>().As<IContainerProvider>().ContainerScoped();
|
||||
|
||||
builder.Register<PackageManager>().As<IPackageManager>()
|
||||
.SingletonScoped();
|
||||
builder.Register<PackageManager>().As<IPackageManager>().SingletonScoped();
|
||||
builder.Register<CorePackageLoader>().As<IPackageLoader>().SingletonScoped();
|
||||
builder.Register<ReferencedPackageLoader>().As<IPackageLoader>().SingletonScoped();
|
||||
builder.Register<PrecompiledPackageLoader>().As<IPackageLoader>().SingletonScoped();
|
||||
builder.Register<DynamicPackageLoader>().As<IPackageLoader>().SingletonScoped();
|
||||
|
||||
//builder.Register((ctx, p) => new PackageFolders(MapPaths(p.Named<IEnumerable<string>>("paths"))))
|
||||
// .As<IPackageFolders>()
|
||||
|
@@ -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<HttpContextBase>()
|
||||
.FactoryScoped();
|
||||
}
|
||||
|
@@ -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<PackageEntry> _packages;
|
||||
|
||||
public OrchardControllerIdentificationStrategy(IEnumerable<PackageEntry> 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;
|
||||
}
|
||||
|
@@ -189,6 +189,11 @@
|
||||
<Compile Include="Mvc\ViewPage.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Packages\Loaders\DynamicPackageLoader.cs" />
|
||||
<Compile Include="Packages\Loaders\PrecompiledPackageLoader.cs" />
|
||||
<Compile Include="Packages\Loaders\CorePackageLoader.cs" />
|
||||
<Compile Include="Packages\Loaders\IPackageLoader.cs" />
|
||||
<Compile Include="Packages\Loaders\ReferencedPackageLoader.cs" />
|
||||
<Compile Include="Security\IAuthenticationService.cs" />
|
||||
<Compile Include="Security\Authorizer.cs" />
|
||||
<Compile Include="Security\Providers\FormsAuthenticationService.cs" />
|
||||
|
28
src/Orchard/Packages/Loaders/CorePackageLoader.cs
Normal file
28
src/Orchard/Packages/Loaders/CorePackageLoader.cs
Normal file
@@ -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 + ".");
|
||||
}
|
||||
}
|
||||
}
|
58
src/Orchard/Packages/Loaders/DynamicPackageLoader.cs
Normal file
58
src/Orchard/Packages/Loaders/DynamicPackageLoader.cs
Normal file
@@ -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<string> GetAssemblyReferenceNames() {
|
||||
return BuildManager.GetReferencedAssemblies()
|
||||
.OfType<Assembly>()
|
||||
.Select(x => x.Location)
|
||||
.Where(x => !string.IsNullOrEmpty(x))
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
private IEnumerable<string> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
src/Orchard/Packages/Loaders/IPackageLoader.cs
Normal file
6
src/Orchard/Packages/Loaders/IPackageLoader.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Orchard.Packages.Loaders {
|
||||
public interface IPackageLoader {
|
||||
int Order { get; }
|
||||
PackageEntry Load(PackageDescriptor descriptor);
|
||||
}
|
||||
}
|
21
src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs
Normal file
21
src/Orchard/Packages/Loaders/PrecompiledPackageLoader.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
31
src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs
Normal file
31
src/Orchard/Packages/Loaders/ReferencedPackageLoader.cs
Normal file
@@ -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<Assembly>()
|
||||
.FirstOrDefault(x=>x.GetName().Name == descriptor.Name);
|
||||
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
return new PackageEntry {
|
||||
Descriptor = descriptor,
|
||||
Assembly = assembly,
|
||||
ExportedTypes = assembly.GetExportedTypes()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -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<IPackageLoader> _loaders;
|
||||
private IEnumerable<PackageEntry> _activePackages;
|
||||
|
||||
public PackageManager(IPackageFolders folders) {
|
||||
public PackageManager(IPackageFolders folders, IEnumerable<IPackageLoader> loaders) {
|
||||
_folders = folders;
|
||||
_loaders = loaders.OrderBy(x => x.Order);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,35 +52,28 @@ namespace Orchard.Packages {
|
||||
}
|
||||
|
||||
public IEnumerable<PackageEntry> ActivePackages() {
|
||||
if (_activePackages == null) {
|
||||
_activePackages = BuildActivePackages().ToList();
|
||||
}
|
||||
return _activePackages;
|
||||
}
|
||||
|
||||
private IEnumerable<PackageEntry> 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 + ".");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user