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:
loudej
2009-12-01 21:29:16 +00:00
parent 299ba38dfb
commit ae2a157b52
13 changed files with 201 additions and 30 deletions

View File

@@ -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"));

View File

@@ -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();

View File

@@ -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 &&

View File

@@ -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>()

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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" />

View 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 + ".");
}
}
}

View 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;
}
}
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.Packages.Loaders {
public interface IPackageLoader {
int Order { get; }
PackageEntry Load(PackageDescriptor descriptor);
}
}

View 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;
}
}
}

View 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()
};
}
}
}

View File

@@ -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 + ".");
}
}
}