为了说明自定义虚拟路径,这里弄个示例,仅仅用一个压缩包存放一个网站的多个文件。
这个东西是要需要通过实现3个抽象类来实现:
- System.Web.Hosting.VirtualPathProvider;
- System.Web.Hosting.VirtualDirectory;
- System.Web.Hosting.VirtualFile;
因为,我真的不知道如何去缩减,代码比较多。首先新建一个Web项目,然后添加如下3个类:
1、虚拟目录提供者类:
public class ZipVirtualPathProvider : System.Web.Hosting.VirtualPathProvider{private string fileRootPath; private string virtualRootPath; private ZipVirtualDirectory root; public ZipVirtualPathProvider() { this.fileRootPath = HttpRuntime.AppDomainAppPath; this.virtualRootPath = HttpRuntime.AppDomainAppVirtualPath + "/"; string path = string.Format("{0}App_Data\\test.zip", fileRootPath); using (ZipFile zipFile = new ZipFile(path)) { // 创建根目录 this.root = new ZipVirtualDirectory(virtualRootPath); foreach (ICSharpCode.SharpZipLib.Zip.ZipEntry entry in zipFile) { string name = string.Format("{0}{1}", this.virtualRootPath, entry.Name); VirtualDirectory parent = GetParentDirectory(name); ZipVirtualDirectory zipParent = parent as ZipVirtualDirectory; System.Web.Hosting.VirtualFileBase vfb; if (entry.IsDirectory) { vfb = new ZipVirtualDirectory(name); } else { System.IO.Stream stream = zipFile.GetInputStream(entry); int size = (int)entry.Size; byte[] buffer = ReadAllBytes(stream, size); vfb = new ZipVirtualFile(name, buffer); } zipParent.AddVirtualItem(vfb); } } } //寻找子目录所属的父目录 private VirtualDirectory GetParentDirectory(string virtualPath) { // 从根目录开始找,直到找不到为止,说明就是所属的父目录,加入父目录中 VirtualDirectory root = this.root; while (true) { bool isContinue = false; foreach (VirtualDirectory dir in root.Directories) { if (virtualPath.StartsWith(dir.VirtualPath)) { root = dir; isContinue = true; break; } } if (isContinue) continue; // 如果都不是,那么,当前的 root 就是其父目录 return root; } } //是否存在目录 public override bool DirectoryExists(string virtualDir) { /// 从根目录开始递归寻找 bool result = SearchDirectory(this.root, virtualDir); if (result) { return true; } return this.Previous.DirectoryExists(virtualDir); } //搜索目录 private bool SearchDirectory(VirtualDirectory parent, string virtualDir) { if (parent.Name == virtualDir) { return true; } foreach (VirtualDirectory child in parent.Directories) { bool result = SearchDirectory(child, virtualDir); if (result) { return true; } } return false; } //判断文件是否存在 public override bool FileExists(string virtualPath) { //只检查压缩包的一级目录(有就有,没有就没有) foreach (VirtualFile file in this.root.Files) { if (file.Name.Replace("//", "/") == virtualPath) { return true; } } return this.Previous.FileExists(virtualPath); } public override System.Web.Hosting.VirtualDirectory GetDirectory(string virtualDir) { VirtualDirectory dir = GetParentDirectory(virtualDir); // 不存在的话,找到父目录,存在的话,找到自己。 bool exist = dir.VirtualPath == virtualDir; if (exist) { return dir; } return this.Previous.GetDirectory(virtualDir); } public override System.Web.Hosting.VirtualFile GetFile(string virtualPath) { //找到可能存在的目录 VirtualDirectory dir = GetParentDirectory(virtualPath); // 遍历查找 foreach (VirtualFile file in dir.Files) { if (file.VirtualPath == virtualPath) { return file; } } return this.Previous.GetFile(virtualPath); } public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart) { // 由于采用了压缩文件,所以不生成缓存依赖对象 return null; } private byte[] ReadAllBytes(System.IO.Stream stream, int size) { byte[] buffer = new byte[size]; int count = stream.Read(buffer, 0, size); return buffer; } }
虚拟目录与虚拟文件类:
public class ZipVirtualDirectory : System.Web.Hosting.VirtualDirectory{//保存文件夹中包含的子项目的集合 //包括文件和子目录 private List<VirtualFileBase> items; private List<VirtualFile> files; private List<VirtualDirectory> directories; private string name; public override System.Collections.IEnumerable Files { get { return this.files; } } public override System.Collections.IEnumerable Children { get { return this.items; } } public override System.Collections.IEnumerable Directories { get { return directories; } } public override string Name { get { return base.Name; } } public ZipVirtualDirectory(string name) : base(name) { this.items = new List<VirtualFileBase>(); this.directories = new List<VirtualDirectory>(); this.files = new List<VirtualFile>(); this.name = name; } // 在目录中增加一个项目 public void AddVirtualItem(VirtualFileBase item) { this.items.Add(item); if (item.IsDirectory) { this.directories.Add(item as VirtualDirectory); } else { this.files.Add(item as VirtualFile); } } } public class ZipVirtualFile : System.Web.Hosting.VirtualFile { public override string Name { get { return this.name; } } public override System.IO.Stream Open() { return new System.IO.MemoryStream(this.buffer); } private string name; private byte[] buffer; public ZipVirtualFile(string name, byte[] buffer) : base(name) { this.name = name; this.buffer = buffer; } }
注册虚拟目录提供程序,在App_Code目录里面添加一个AppStart类:
public class AppStart{public static void AppInitialize() { ZipVirtualPathProvider virtualPathProvider = new ZipVirtualPathProvider(); System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(virtualPathProvider); } }
然后新建一个zip压缩包,里面有如下两个页面:
然后启动项目,打开路径:/test/1.html。
网站程序中是不存在"test"这个目录的,但是自定义的虚拟目录将对此路径的访问映射到"test.zip"里面的1.html去了。这就是自定义虚拟路径提供器的强大之处。