Create a virtual path provider for WebForms files

This is so that we dynamically add the relevant <%@ Assembly Name="" %>
directive to WebForms files served from modules which have been dynamically
compiled and stored in the "~/App_Data/Dependencies" folder.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-06-04 22:28:01 -07:00
parent 2be308bbf6
commit 1efde731fe
4 changed files with 133 additions and 4 deletions

View File

@@ -3,13 +3,12 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Web; using System.Web;
using System.Web.Hosting;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using Autofac; using Autofac;
using Autofac.Builder;
using Autofac.Integration.Web;
using Autofac.Integration.Web.Mvc;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Environment.Extensions.Loaders;
namespace Orchard.Web { namespace Orchard.Web {
// Note: For instructions on enabling IIS6 or IIS7 classic mode, // Note: For instructions on enabling IIS6 or IIS7 classic mode,
@@ -32,6 +31,7 @@ namespace Orchard.Web {
RegisterRoutes(RouteTable.Routes); RegisterRoutes(RouteTable.Routes);
HostingEnvironment.RegisterVirtualPathProvider(new WebFormsExtensionsVirtualPathProvider());
_host = OrchardStarter.CreateHost(MvcSingletons); _host = OrchardStarter.CreateHost(MvcSingletons);
_host.Initialize(); _host.Initialize();
@@ -101,6 +101,5 @@ namespace Orchard.Web {
builder.RegisterInstance(ModelMetadataProviders.Current); builder.RegisterInstance(ModelMetadataProviders.Current);
builder.RegisterInstance(ViewEngines.Engines); builder.RegisterInstance(ViewEngines.Engines);
} }
} }
} }

View File

@@ -0,0 +1,51 @@
using System.IO;
using System.Reflection;
using System.Web.Hosting;
namespace Orchard.Environment.Extensions.Loaders {
public class WebFormsExtensionsVirtualFile : VirtualFile {
private readonly Assembly _assembly;
private readonly VirtualFile _actualFile;
public WebFormsExtensionsVirtualFile(string virtualPath, Assembly assembly, VirtualFile actualFile)
: base(virtualPath) {
_assembly = assembly;
_actualFile = actualFile;
}
public override string Name {
get {
return _actualFile.Name;
}
}
public override bool IsDirectory {
get {
return _actualFile.IsDirectory;
}
}
public override Stream Open() {
var reader = new StreamReader(_actualFile.Open());
var memoryStream = new MemoryStream();
int length;
using (var writer = new StreamWriter(memoryStream)) {
bool assemblyDirectiveAdded = false;
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) {
if (!string.IsNullOrWhiteSpace(line) && !assemblyDirectiveAdded) {
line += string.Format("<%@ Assembly Name=\"{0}\"%>", _assembly);
assemblyDirectiveAdded = true;
}
writer.WriteLine(line);
}
writer.Flush();
length = (int)memoryStream.Length;
}
var result = new MemoryStream(memoryStream.GetBuffer(), 0, length);
return result;
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Linq;
using System.Web.Hosting;
using Orchard.FileSystems.Dependencies;
namespace Orchard.Environment.Extensions.Loaders {
public class WebFormsExtensionsVirtualPathProvider : VirtualPathProvider {
private IDependenciesFolder _dependenciesFolder;
private const string _prefix1 = "~/Modules/";
private const string _prefix2 = "/Modules/";
public WebFormsExtensionsVirtualPathProvider() {
}
protected override void Initialize() {
base.Initialize();
_dependenciesFolder = new DefaultDependenciesFolder(new DefaultVirtualPathProvider());
}
public override bool DirectoryExists(string virtualDir) {
return Previous.DirectoryExists(virtualDir);
}
public override bool FileExists(string virtualPath) {
return Previous.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath) {
var actualFile = Previous.GetFile(virtualPath);
var prefix = PrefixMatch(virtualPath);
if (prefix == null)
return actualFile;
var extension = ExtensionMatch(virtualPath, ".ascx", ".aspx", ".master");
if (extension == null)
return actualFile;
var moduleName = ModuleMatch(virtualPath, prefix);
if (moduleName == null)
return actualFile;
// It looks like we have a module name. Is this one of this modules
// with its assembly stored in the "App_Data/Dependencies" folder?
var assembly = _dependenciesFolder.LoadAssembly(moduleName);
if (assembly == null)
return actualFile;
// Yes: we need to wrap the VirtualFile to add the <%@ Assembly Name=".."%> directive
// in the content.
return new WebFormsExtensionsVirtualFile(virtualPath, assembly, actualFile);
}
private string ModuleMatch(string virtualPath, string prefix) {
var index = virtualPath.IndexOf('/', prefix.Length, virtualPath.Length - prefix.Length);
if (index < 0)
return null;
var moduleName = virtualPath.Substring(prefix.Length, index - prefix.Length);
return (string.IsNullOrEmpty(moduleName) ? null : moduleName);
}
private string ExtensionMatch(string virtualPath, params string[] extensions) {
return extensions
.FirstOrDefault(e => virtualPath.EndsWith(e, StringComparison.OrdinalIgnoreCase));
}
private string PrefixMatch(string virtualPath) {
if (virtualPath.StartsWith(_prefix1))
return _prefix1;
if (virtualPath.StartsWith(_prefix2))
return _prefix2;
return null;
}
}
}

View File

@@ -341,6 +341,8 @@
<Compile Include="Data\DataModule.cs" /> <Compile Include="Data\DataModule.cs" />
<Compile Include="Data\Orderable.cs" /> <Compile Include="Data\Orderable.cs" />
<Compile Include="Environment\DefaultOrchardShell.cs" /> <Compile Include="Environment\DefaultOrchardShell.cs" />
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualPathProvider.cs" />
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualFile.cs" />
<Compile Include="Environment\IHostEnvironment.cs" /> <Compile Include="Environment\IHostEnvironment.cs" />
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" /> <Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" /> <Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />