为了说明自定义虚拟路径,这里弄个示例,仅仅用一个压缩包存放一个网站的多个文件。
这个东西是要需要通过实现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去了。这就是自定义虚拟路径提供器的强大之处。