Module loading strategies

Make the precompiled and dynamic extension loaders work properly
and also refactor some code to introduce proper abstractions, such
as IVirtualPathProvider, IHostEnvironment, IBuildManager, etc.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-06-04 19:13:57 -07:00
parent abe6c67b25
commit a1be3efecb
21 changed files with 355 additions and 147 deletions

View File

@@ -28,7 +28,7 @@
-->
<compilation debug="true" targetFramework="4.0">
<buildProviders>
<add extension=".csproj" type="Orchard.Environment.Extensions.Loaders.CSharpExtensionBuildProvider"/>
<add extension=".csproj" type="Orchard.Environment.Extensions.Compilers.CSharpExtensionBuildProvider"/>
</buildProviders>
<assemblies>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

View File

@@ -1,6 +1,6 @@
using System.Web.Compilation;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment.Extensions.Compilers {
public class CSharpExtensionBuildProvider : BuildProvider {
private readonly CompilerType _codeCompilerType;
@@ -11,7 +11,7 @@ namespace Orchard.Environment.Extensions.Loaders {
public override CompilerType CodeCompilerType { get { return _codeCompilerType; } }
public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
var virtualPathProvider = new AspNetVirtualPathProvider();
var virtualPathProvider = new DefaultVirtualPathProvider();
var compiler = new CSharpProjectMediumTrustCompiler(virtualPathProvider);
var aspNetAssemblyBuilder = new AspNetAssemblyBuilder(assemblyBuilder, this);

View File

@@ -4,9 +4,8 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using System.Web.Hosting;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment.Extensions.Compilers {
/// <summary>
/// Compile a C# extension into an assembly given a directory location
/// </summary>

View File

@@ -1,9 +1,9 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment.Extensions.Compilers {
/// <summary>
/// Compile a C# extension into an assembly given a directory location
/// </summary>
@@ -20,15 +20,17 @@ namespace Orchard.Environment.Extensions.Loaders {
/// Compile a csproj file given its virtual path. Use the CSharp CodeDomProvider
/// class, which is only available in full trust.
/// </summary>
public CompilerResults CompileProject(string virtualPath) {
public CompilerResults CompileProject(string virtualPath, string outputDirectory) {
var codeProvider = CodeDomProvider.CreateProvider("cs");
var directory = _virtualPathProvider.GetDirectoryName(virtualPath);
using (var stream = _virtualPathProvider.OpenFile(virtualPath)) {
var descriptor = new CSharpProjectParser().Parse(stream);
var references = GetAssemblyReferenceNames();
var references = GetReferencedAssembliesLocation();
var options = new CompilerParameters(references.ToArray());
options.GenerateExecutable = false;
options.OutputAssembly = Path.Combine(outputDirectory, descriptor.AssemblyName + ".dll");
var fileNames = descriptor.SourceFilenames
.Select(f => _virtualPathProvider.Combine(directory, f))
@@ -39,11 +41,10 @@ namespace Orchard.Environment.Extensions.Loaders {
}
}
private IEnumerable<string> GetAssemblyReferenceNames() {
private IEnumerable<string> GetReferencedAssembliesLocation() {
return _buildManager.GetReferencedAssemblies()
.OfType<Assembly>()
.Where(a => !string.IsNullOrEmpty(a.Location))
.Select(a => a.Location)
.Where(a => !string.IsNullOrEmpty(a))
.Distinct();
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System.CodeDom;
using System.CodeDom;
using System.IO;
using System.Linq;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment.Extensions.Compilers {
/// <summary>
/// Compile a C# extension into an assembly given a directory location
/// </summary>

View File

@@ -4,25 +4,40 @@ using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment.Extensions.Compilers {
public class CSharpProjectDescriptor {
public string AssemblyName { get; set; }
public IEnumerable<string> SourceFilenames { get; set; }
public IEnumerable<ReferenceDescriptor> References { get; set; }
}
public class ReferenceDescriptor {
public string AssemblyName { get; set; }
public override string ToString() {
return "{" + (AssemblyName ?? "") + "}";
}
}
public class CSharpProjectParser {
public CSharpProjectDescriptor Parse(Stream stream) {
var document = XDocument.Load(XmlReader.Create(stream));
return new CSharpProjectDescriptor {
SourceFilenames = GetSourceFilenames(document),
References = GetReferences(document)
AssemblyName = GetAssemblyName(document),
SourceFilenames = GetSourceFilenames(document).ToArray(),
References = GetReferences(document).ToArray()
};
}
private string GetAssemblyName(XDocument document) {
return document
.Elements(ns("Project"))
.Elements(ns("PropertyGroup"))
.Elements(ns("AssemblyName"))
.Single()
.Value;
}
private IEnumerable<string> GetSourceFilenames(XDocument document) {
return document
.Elements(ns("Project"))

View File

@@ -5,7 +5,7 @@ using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Loaders {
public class AreaExtensionLoader : IExtensionLoader {
public int Order { get { return 5; } }
public int Order { get { return 50; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
if (descriptor.Location == "~/Areas") {

View File

@@ -4,12 +4,14 @@ using System.Reflection;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Loaders {
/// <summary>
/// Load an extension by looking into specific namespaces of the "Orchard.Core" assembly
/// </summary>
public class CoreExtensionLoader : IExtensionLoader {
public int Order { get { return 1; } }
public int Order { get { return 10; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
if (descriptor.Location == "~/Core") {
var assembly = Assembly.Load("Orchard.Core");
return new ExtensionEntry {
Descriptor = descriptor,

View File

@@ -1,64 +1,36 @@
using System;
using System.IO;
using System.Reflection;
using System.Web.Compilation;
using System.Web.Hosting;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
namespace Orchard.Environment.Extensions.Loaders {
public class DynamicExtensionLoader : IExtensionLoader {
public int Order { get { return 10; } }
private readonly IHostEnvironment _hostEnvironment;
private readonly IBuildManager _buildManager;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IDependenciesFolder _dependenciesFolder;
public DynamicExtensionLoader(IHostEnvironment hostEnvironment, IBuildManager buildManager, IVirtualPathProvider virtualPathProvider, IDependenciesFolder dependenciesFolder) {
_hostEnvironment = hostEnvironment;
_buildManager = buildManager;
_virtualPathProvider = virtualPathProvider;
_dependenciesFolder = dependenciesFolder;
}
public int Order { get { return 100; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
if (HostingEnvironment.IsHosted == false)
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name,
descriptor.Name + ".csproj");
if (!_virtualPathProvider.FileExists(projectPath)) {
return null;
// 1) Try to load the assembly directory
// This will look in the "App_Data/Dependencies" directory if
// the probing path is correctly configured in Web.config
{
try {
Assembly assembly = Assembly.Load(descriptor.Name);
return CreateExtensionEntry(descriptor, assembly);
}
catch (FileNotFoundException e) {
// The assembly is not in one of the probing directory,
// including "App_Data/Dependencies", we need to move on
// to other strageties
}
}
// 2) look for the assembly in the "Bin" directory
{
string modulePath = HostingEnvironment.MapPath(descriptor.Location);
modulePath = Path.Combine(modulePath, descriptor.Name);
string moduleBinary = Path.Combine(modulePath, "bin");
moduleBinary = Path.Combine(moduleBinary, descriptor.Name + ".dll");
if (File.Exists(moduleBinary)) {
// Copy file to dependencies directory
string dependenciesPath = HostingEnvironment.MapPath("~/App_Data/Dependencies");
if (!Directory.Exists(dependenciesPath)) {
Directory.CreateDirectory(dependenciesPath);
}
string destFile = Path.Combine(dependenciesPath, descriptor.Name + ".dll");
File.Copy(moduleBinary, destFile, true);
var assembly = _buildManager.GetCompiledAssembly(projectPath);
// then load the assembly
Assembly assembly = Assembly.Load(descriptor.Name);
return CreateExtensionEntry(descriptor, assembly);
}
if (_hostEnvironment.IsFullTrust) {
_dependenciesFolder.StoreAssemblyFile(descriptor.Name, assembly.Location);
}
// 3) look for the csproj in the module directory
{
string projfileName = Path.Combine(descriptor.Location, descriptor.Name);
projfileName = Path.Combine(projfileName, descriptor.Name + ".csproj").Replace('\\', '/');
var assembly = BuildManager.GetCompiledAssembly(projfileName);
return CreateExtensionEntry(descriptor, assembly);
}
}
private static ExtensionEntry CreateExtensionEntry(ExtensionDescriptor descriptor, Assembly assembly) {
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly,

View File

@@ -1,16 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Compilation;
namespace Orchard.Environment.Extensions.Loaders {
public interface IBuildManager {
IEnumerable<string> GetReferencedAssemblies();
}
public class AspNetBuildManager : IBuildManager {
public IEnumerable<string> GetReferencedAssemblies() {
return BuildManager.GetReferencedAssemblies().Cast<string>();
}
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.IO;
using System.Web.Hosting;
namespace Orchard.Environment.Extensions.Loaders {
public interface IVirtualPathProvider {
string GetDirectoryName(string virtualPath);
string Combine(params string[] paths);
Stream OpenFile(string virtualPath);
string MapPath(string virtualPath);
}
public class AspNetVirtualPathProvider : IVirtualPathProvider {
public string GetDirectoryName(string virtualPath) {
return Path.GetDirectoryName(virtualPath);
}
public string Combine(params string[] paths) {
return Path.Combine(paths).Replace('\\', '/');
}
public Stream OpenFile(string virtualPath) {
return VirtualPathProvider.OpenFile(virtualPath);
}
public string MapPath(string virtualPath) {
return HostingEnvironment.MapPath(virtualPath);
}
}
}

View File

@@ -1,17 +1,39 @@
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
namespace Orchard.Environment.Extensions.Loaders {
/// <summary>
/// Load an extension by looking into the "bin" subdirectory of an
/// extension directory.
/// </summary>
public class PrecompiledExtensionLoader : IExtensionLoader {
public int Order { get { return 3; } }
private readonly IDependenciesFolder _folder;
private readonly IVirtualPathProvider _virtualPathProvider;
public PrecompiledExtensionLoader(IDependenciesFolder folder, IVirtualPathProvider virtualPathProvider) {
_folder = folder;
_virtualPathProvider = virtualPathProvider;
}
public int Order { get { return 40; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
//var assembly = Assembly.Load(descriptor.Name);
//return new ModuleEntry {
// Descriptor = descriptor,
// Assembly = assembly,
// ExportedTypes = assembly.GetExportedTypes()
//};
var extensionPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, "bin",
descriptor.Name + ".dll");
if (!_virtualPathProvider.FileExists(extensionPath))
return null;
_folder.StoreAssemblyFile(descriptor.Name, _virtualPathProvider.MapPath(extensionPath));
var assembly = _folder.LoadAssembly(descriptor.Name);
if (assembly == null)
return null;
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly,
ExportedTypes = assembly.GetExportedTypes()
};
}
}
}

View File

@@ -0,0 +1,30 @@
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
namespace Orchard.Environment.Extensions.Loaders {
/// <summary>
/// Load an extension using the "Assembly.Load" method if the
/// file can be found in the "App_Data/Dependencies" folder.
/// </summary>
public class ProbingExtensionLoader : IExtensionLoader {
private readonly IDependenciesFolder _folder;
public ProbingExtensionLoader(IDependenciesFolder folder) {
_folder = folder;
}
public int Order { get { return 30; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
var assembly = _folder.LoadAssembly(descriptor.Name);
if (assembly == null)
return null;
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly,
ExportedTypes = assembly.GetExportedTypes()
};
}
}
}

View File

@@ -5,8 +5,11 @@ using System.Web.Hosting;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Loaders {
/// <summary>
/// Load an extension by looking through the BuildManager referenced assemblies
/// </summary>
public class ReferencedExtensionLoader : IExtensionLoader {
public int Order { get { return 2; } }
public int Order { get { return 20; } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
if (HostingEnvironment.IsHosted == false)

View File

@@ -1,7 +1,7 @@
using System.CodeDom;
using System.Web.Compilation;
namespace Orchard.Environment.Extensions.Loaders {
namespace Orchard.Environment {
public interface IAssemblyBuilder {
void AddCodeCompileUnit(CodeCompileUnit compileUnit);
}

View File

@@ -0,0 +1,21 @@
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Compilation;
namespace Orchard.Environment {
public interface IBuildManager : IDependency {
IEnumerable<Assembly> GetReferencedAssemblies();
Assembly GetCompiledAssembly(string virtualPath);
}
public class DefaultBuildManager : IBuildManager {
public IEnumerable<Assembly> GetReferencedAssemblies() {
return BuildManager.GetReferencedAssemblies().OfType<Assembly>();
}
public Assembly GetCompiledAssembly(string virtualPath) {
return BuildManager.GetCompiledAssembly(virtualPath);
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Web.Hosting;
namespace Orchard.Environment {
/// <summary>
/// Abstraction of the running environment
/// </summary>
public interface IHostEnvironment : IDependency {
bool IsFullTrust { get; }
string MapPath(string virtualPath);
}
public class DefaultHostEnvironment : IHostEnvironment {
public bool IsFullTrust {
get { return AppDomain.CurrentDomain.IsFullyTrusted; }
}
public string MapPath(string virtualPath) {
return HostingEnvironment.MapPath(virtualPath);
}
}
}

View File

@@ -0,0 +1,50 @@
using System.IO;
using System.Web.Hosting;
using Orchard.Caching;
namespace Orchard.Environment {
public interface IVirtualPathProvider : IVolatileProvider {
string GetDirectoryName(string virtualPath);
string Combine(params string[] paths);
Stream OpenFile(string virtualPath);
StreamWriter CreateText(string virtualPath);
string MapPath(string virtualPath);
bool FileExists(string virtualPath);
bool DirectoryExists(string virtualPath);
void CreateDirectory(string virtualPath);
}
public class DefaultVirtualPathProvider : IVirtualPathProvider {
public string GetDirectoryName(string virtualPath) {
return Path.GetDirectoryName(virtualPath).Replace('\\', '/');
}
public string Combine(params string[] paths) {
return Path.Combine(paths).Replace('\\', '/');
}
public Stream OpenFile(string virtualPath) {
return HostingEnvironment.VirtualPathProvider.GetFile(virtualPath).Open();
}
public StreamWriter CreateText(string virtualPath) {
return File.CreateText(MapPath(virtualPath));
}
public string MapPath(string virtualPath) {
return HostingEnvironment.MapPath(virtualPath);
}
public bool FileExists(string virtualPath) {
return HostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
}
public bool DirectoryExists(string virtualPath) {
return HostingEnvironment.VirtualPathProvider.DirectoryExists(virtualPath);
}
public void CreateDirectory(string virtualPath) {
Directory.CreateDirectory(MapPath(virtualPath));
}
}
}

View File

@@ -15,6 +15,7 @@ using Orchard.Environment.State;
using Orchard.Environment.Topology;
using Orchard.Events;
using Orchard.FileSystems.AppData;
using Orchard.FileSystems.Dependencies;
using Orchard.FileSystems.WebSite;
using Orchard.Logging;
using Orchard.Services;
@@ -30,10 +31,14 @@ namespace Orchard.Environment {
// a single default host implementation is needed for bootstrapping a web app domain
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
RegisterVolatileProvider<Clock, IClock>(builder);
RegisterVolatileProvider<DefaultDependenciesFolder, IDependenciesFolder>(builder);
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().As<IEventHandler>().SingleInstance();
{
@@ -63,6 +68,7 @@ namespace Orchard.Environment {
builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<ProbingExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance();
}
}

View File

@@ -0,0 +1,110 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Orchard.Caching;
using Orchard.Environment;
namespace Orchard.FileSystems.Dependencies {
public interface IDependenciesFolder : IVolatileProvider {
void StoreAssemblyFile(string assemblyName, string assemblyFileName);
Assembly LoadAssembly(string assemblyName);
}
public class DefaultDependenciesFolder : IDependenciesFolder {
private const string _basePath = "~/App_Data/Dependencies";
private readonly IVirtualPathProvider _virtualPathProvider;
public DefaultDependenciesFolder(IVirtualPathProvider virtualPathProvider) {
_virtualPathProvider = virtualPathProvider;
}
private string BasePath {
get {
return _basePath;
}
}
private string PersistencePath {
get {
return _virtualPathProvider.Combine(BasePath, "dependencies.xml");
}
}
public void StoreAssemblyFile(string assemblyName, string assemblyFileName) {
StoreAssemblyFile(assemblyName, assemblyFileName, Path.GetFileName(assemblyFileName));
}
private void StoreAssemblyFile(string assemblyName, string assemblyFileName, string destinationFileName) {
_virtualPathProvider.CreateDirectory(BasePath);
var destinationPath = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, destinationFileName));
File.Copy(assemblyFileName, destinationPath);
StoreDepencyInformation(assemblyName, destinationFileName);
}
private void StoreDepencyInformation(string name, string fileName) {
var dependencies = ReadDependencies().ToList();
var dependency = dependencies.SingleOrDefault(d => d.Name == name);
if (dependency == null) {
dependency = new DependencyDescritpor { Name = name, FileName = fileName };
dependencies.Add(dependency);
}
dependency.FileName = fileName;
WriteDependencies(dependencies);
}
public Assembly LoadAssembly(string assemblyName) {
_virtualPathProvider.CreateDirectory(BasePath);
var dependency = ReadDependencies().SingleOrDefault(d => d.Name == assemblyName);
if (dependency == null)
return null;
if (!_virtualPathProvider.FileExists(_virtualPathProvider.Combine(BasePath, dependency.FileName)))
return null;
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
}
private class DependencyDescritpor {
public string Name { get; set; }
public string FileName { get; set; }
}
private IEnumerable<DependencyDescritpor> ReadDependencies() {
if (!_virtualPathProvider.FileExists(PersistencePath))
return Enumerable.Empty<DependencyDescritpor>();
using (var stream = _virtualPathProvider.OpenFile(PersistencePath)) {
XDocument document = XDocument.Load(stream);
return document
.Elements(ns("Dependencies"))
.Elements(ns("Dependency"))
.Select(e => new DependencyDescritpor { Name = e.Element("Name").Value, FileName = e.Element("FileName").Value })
.ToList();
}
}
private void WriteDependencies(IEnumerable<DependencyDescritpor> dependencies) {
var document = new XDocument();
document.Add(new XElement(ns("Dependencies")));
var elements = dependencies.Select(d => new XElement("Dependency",
new XElement(ns("Name"), d.Name),
new XElement(ns("FileName"), d.FileName)));
document.Root.Add(elements);
using (var stream = _virtualPathProvider.CreateText(PersistencePath)) {
document.Save(stream, SaveOptions.None);
}
}
private static XName ns(string name) {
return XName.Get(name/*, "http://schemas.microsoft.com/developer/msbuild/2003"*/);
}
}
}

View File

@@ -136,14 +136,17 @@
<Compile Include="Data\DataModule.cs" />
<Compile Include="Data\Orderable.cs" />
<Compile Include="Environment\DefaultOrchardShell.cs" />
<Compile Include="Environment\Extensions\Loaders\CSharpExtensionBuildProvider.cs" />
<Compile Include="Environment\Extensions\Loaders\CSharpExtensionCompiler.cs" />
<Compile Include="Environment\Extensions\Loaders\CSharpProjectExtensionCompilerMediumTrust.cs" />
<Compile Include="Environment\Extensions\Loaders\CSharpProjectFullTrustCompiler.cs" />
<Compile Include="Environment\Extensions\Loaders\CSharpProjectParser.cs" />
<Compile Include="Environment\Extensions\Loaders\IAssemblyBuilder.cs" />
<Compile Include="Environment\Extensions\Loaders\IBuildManager.cs" />
<Compile Include="Environment\Extensions\Loaders\IVirtualPathProvider.cs" />
<Compile Include="Environment\IHostEnvironment.cs" />
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
<Compile Include="Environment\Extensions\Compilers\CSharpExtensionBuildProvider.cs" />
<Compile Include="Environment\Extensions\Compilers\CSharpExtensionCompiler.cs" />
<Compile Include="Environment\Extensions\Compilers\CSharpProjectMediumTrustCompiler.cs" />
<Compile Include="Environment\Extensions\Compilers\CSharpProjectFullTrustCompiler.cs" />
<Compile Include="Environment\Extensions\Compilers\CSharpProjectParser.cs" />
<Compile Include="Environment\IAssemblyBuilder.cs" />
<Compile Include="Environment\IBuildManager.cs" />
<Compile Include="Environment\IVirtualPathProvider.cs" />
<Compile Include="Environment\IOrchardShell.cs" />
<Compile Include="Environment\OrchardStarter.cs" />
<Compile Include="Environment\State\DefaultProcessingEngine.cs" />