using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.IO;
using System.Web.Hosting;
using System.Web.Caching;
using System.Collections;
using System.Diagnostics;
namespace HLWebPluginHost.PluginLib {
///
/// The VirtualPathProvider class provides developers a way to intercept the calls MVC makes to
/// retrieve files from the filesystem and provide these files. In our case we look at the plugins
/// directory to find out if it provides the requested ressource.
/// In this case the data is pulled out of the plugin and returned if it was a file.
/// In Fact this class provides parts of the routing and dispatching mechanism known from other mvc frameworks.
///
public class AssemblyResourceProvider : System.Web.Hosting.VirtualPathProvider {
///
/// FileExists() is called by the framework to check for the existence of a physical file.
/// We want to override the method so we can check for the “~/Plugins/” string in our path.
/// If we find it, then we use reflection to determine if we have an embedded view in the targeted assembly that matches the requested file name.
/// An example of a parameter that would be passed into this method would be “~/Plugins/FzySqrPlugin.dll/FzySqrPlugin.Views.HelloWorld.Index.aspx”.
/// Given this path for a view, this code would load the FzySqrPlugin.dll and look for a resource with named FzySqrPlugin.Views.HelloWorld.Index.aspx.
/// If the”~/Plugins/” string is not found, then the super class’s FileExist() method is called and the normal behavior takes place.
///
///
///
public override bool FileExists(string virtualPath) {
if (IsAppResourcePath(virtualPath)) {
string path = VirtualPathUtility.ToAppRelative(virtualPath);
string[] parts = path.Split('/');
string assemblyName = parts[2];
string resourceName = parts[3];
assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
byte[] assemblyBytes = File.ReadAllBytes(assemblyName);
Assembly assembly = Assembly.Load(assemblyBytes);
if (assembly != null) {
string[] resourceList = assembly.GetManifestResourceNames();
bool found = Array.Exists(resourceList, delegate(string r) { return r.Equals(resourceName); });
return found;
}
return false;
} else
return base.FileExists(virtualPath);
}
///
/// If we have a plugin path, then return our custom AssemblyResourceVirtualFile type,
/// otherwise provide the standard behavior.
///
///
///
public override VirtualFile GetFile(string virtualPath) {
if (IsAppResourcePath(virtualPath)) {
return new AssemblyResourceVirtualFile(virtualPath);
} else {
return base.GetFile(virtualPath);
}
}
///
/// If we have a plugin path, return null (for now), otherwise invoke the super class’s method.
///
///
///
///
///
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) {
if (IsAppResourcePath(virtualPath)) {
return null;
}
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
///
/// check a virtual path and decide whether the resource is provided by the plugin or the plugin host.
/// To do this, we use the convention that all paths destined for plugin modules will begin with “~/Plugins/”.
/// In other words, the path ~/Plugins/MyPlugin.dll/SomeResource.aspx indicates that the resource it represents
/// is not a physical file and needs to be loaded from the MyPlugin.dll.
///
///
/// True if a ressource at a given path is an app ressource
private bool IsAppResourcePath(string virtualPath) {
String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
return checkPath.StartsWith("~/Plugins/", StringComparison.InvariantCultureIgnoreCase);
}
}
}