• Asp.Net中虚拟文件系统的使用


    在Asp.Net的开发过程中页面文件等都是放在当前网站目录下的,其实我们可以利用.Net2.0新增的虚拟文件系统(VirtualPathProvider)将页面、图片等信息保存到数据库或其他目录中去,达到灵活配置。
    本文以一个例子来说明虚拟文件系统的使用,要实现的功能场景描述如下:
    以前开发Asp.Net的web用户控件时,需要把用户控件和当前项目作为同一个项目时才能正常使用,而且发布时需要把dll文件和所有的ascx文件都发布才能使用;另外也不方便作为公用类给其他人使用
    利用虚拟文件系统后可以把ascx文件作为资源打包到dll中,下次只要有这个dll就可以使用了,不需要ascx文件,很方便。

    具体实现步骤如下:
    一、开发web用户控件
    这一步和以前的开发没有区别。
    1、首先新建一个web应用程序(需要VS2005 sp1支持)
    2、然后在里面开发几个web用户控件
    3、在ascx文件上右键-〉属性-〉生成操作选择嵌入的资源
    4、生成dll就可以了(dll的名字为:Test.Control.dll,后面会用到)

    二、开发一个虚拟文件系统提供类
    这一步是最重要的一步。
    具体思路就是:在系统中注册这个类,然后在每访问一个文件/资源的时候会自动调用这个类,在这个类中判断文件的路径是否是我们定义的,如果是就用我们的逻辑来处理,即从dll中取出资源。
    首先把类的代码贴出来,我想可能许多人应该和我一样,喜欢直接先看代码:)


        public class DllVirtualPathProvider : System.Web.Hosting.VirtualPathProvider
        
    {
            
    public DllVirtualPathProvider()
            
    {
            }


            
    public override string CombineVirtualPaths(string basePath, string relativePath)
            
    {
                
    if (IsAppResourcePath(basePath))
                
    {
                    
    return null;
                }


                
    return Previous.CombineVirtualPaths(basePath, relativePath);
            }


            
    public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
            
    {
                
    return Previous.CreateObjRef(requestedType);
            }


            
    public override bool DirectoryExists(string virtualDir)
            
    {
                
    if (IsAppResourcePath(virtualDir))
                
    {
                    
    return true;
                }

                
    else
                
    {
                    
    return Previous.DirectoryExists(virtualDir);
                }


            }


            
    public override string GetCacheKey(string virtualPath)
            
    {
                
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    return null;
                }

                
    else
                
    {
                    
    return Previous.GetCacheKey(virtualPath);
                }

            }


            
    public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
            
    {
                
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    return null;
                }

                
    else
                
    {
                    
    return Previous.GetFileHash(virtualPath, virtualPathDependencies);
                }

            }


            
    private bool IsAppResourcePath(string virtualPath)
            
    {
                String checkPath 
    = VirtualPathUtility.ToAppRelative(virtualPath);
                
    return checkPath.StartsWith("~/MyUserControl/Test.Control.dll/", StringComparison.InvariantCultureIgnoreCase);
            }


            
    public override bool FileExists(string virtualPath)
            
    {
                
    return (IsAppResourcePath(virtualPath) || Previous.FileExists(virtualPath));
            }


            
    public override VirtualFile GetFile(string virtualPath)
            
    {
                
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    return new AssemblyResourceVirtualFile(virtualPath);
                }

                
    else
                
    {
                    
    return Previous.GetFile(virtualPath);
                }

            }


            
    public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath,
                   System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
            
    {
                
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    string path = HttpRuntime.AppDomainAppPath + virtualPath.Substring(1);

                    
    return new System.Web.Caching.CacheDependency(path);
                }

                
    else
                
    {
                    
    return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
                }

            }

        }
    重点有以下几个:
    1、必须从VirtualPathProvider类继承
    2、IsAppResourcePath方法是用来判断是否为我们定义的路径格式:~/MyUserControl/Test.Control.dll/,下面调用的时候就使用这个路径
    3、注意GetCacheKey方法:
            public override string GetCacheKey(string virtualPath)
            
    {
                
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    return null;
                }

                
    else
                
    {
                    
    return Previous.GetCacheKey(virtualPath);
                }

            }
    这里当符合条件时一定要返回null,如果返回"",会导致所有的用户控件都使用一个key值,从而所有的用户控件都显示同样的内容了。如果返回其他非空字符,会报异常(它会去查找cache,我们是没有的)
    另外所有的方法当不符合我们的条件时一定要调用 Previous.**** 因为系统中可能有多个虚拟文件提供程序的。

    4、GetCacheDependency方法:
    if (IsAppResourcePath(virtualPath))
                
    {
                    
    string path = HttpRuntime.AppDomainAppPath + virtualPath.Substring(1);

                    
    return new System.Web.Caching.CacheDependency(path);
                }
    这个方法是用来决定Cache的使用的,如果返回null,会导致性能严重下降,每次调用用户控件时都会重新编译,这里返回的当前路径(需要在网站目录下再建立子目录:MyUserControl"Test.Control.dll),这个目录下是空的,这样当每次取Cache时都会认为我们的ascx没有修改,不需要重新编译。

    5、在GetFile方法中我们返回的是一个AssemblyResourceVirtualFile类:
        class AssemblyResourceVirtualFile : VirtualFile
        
    {
            
    string path;
            
    public AssemblyResourceVirtualFile(string virtualPath)
                : 
    base(virtualPath)
            
    {
                path 
    = VirtualPathUtility.ToAppRelative(virtualPath);
            }


            
    public override System.IO.Stream Open()
            
    {
                
    string[] parts = path.Split('/');
                
    string assemblyName = parts[2];
                
    string resourceName = parts[3];
                assemblyName 
    = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
                System.Reflection.Assembly assembly 
    = System.Reflection.Assembly.LoadFrom(assemblyName);
                
    if (assembly != null)
                
    {
                    
    return assembly.GetManifestResourceStream(resourceName);
                }

                
    return null;
            }

        }
    这个类的目的就是从我们的dll中读出资源文件。

    三、注册这个虚拟文件提供程序
    这一个很简单,在global.asax中注册:
            protected void Application_Start(object sender, EventArgs e)
            
    {
                System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(
    new DllVirtualPathProvider());
            }

    四、调用dll中的用户控件
                    Control control1 = this.LoadControl("/MyUserControl/Test.Control.dll/Test.Control.Sample.List.ascx");
                    Control control2 
    = this.LoadControl("/MyUserControl/Test.Control.dll/Test.Control.Sample.Sample.ascx");

                    form1.Controls.Add(control1);
                    form1.Controls.Add(control2);
    比较简单,就是路径要和前面的一致。

    后记:
    首先感谢 Leepy  同志认真踏实的精神,找出了我这篇文章中的一个BUG。
    原来我的第四步:调用dll中的用户控件,是一个web应用程序,如果是一个web站点的话就会出现问题。因为在VS2005中调试时这两种方式呈现出来的Url是不一样的:
    web应用程序:http://localhost:****/Default.aspx
    web站点     :http://localhost:****/WebSite1/Default.aspx
    也就是说我原来的程序没有考虑到非根目录部署的情况,针对这个BUG要修改的地方有(为了BUG的原始记录,我就不在原文中修改了,把修改点列在下面):
    1、GetCacheDependency方法:

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath,
               System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        
    {
            
    if (IsAppResourcePath(virtualPath))
            
    {
                
    string path = HttpRuntime.BinDirectory;

                
    return new System.Web.Caching.CacheDependency(path);
            }

            
    else
            
    {
                
    return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
            }

        }
    这里改成直接改成当前网站的bin目录还可以省掉建空目录的步骤了

    2、在调用的地方修改成以下方式:
            Control control1 = this.LoadControl("~/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample1.ascx");
            Control control2 
    = this.LoadControl("~/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample2.ascx");

            form1.Controls.Add(control1);
            form1.Controls.Add(control2);
  • 相关阅读:
    连通块问题
    线性数据结构
    NOIP2018总结
    原码反码补码详解
    一些常用的算法技巧总结
    骗分导论
    模板
    模板
    AcWing
    AcWing
  • 原文地址:https://www.cnblogs.com/leeolevis/p/1383185.html
Copyright © 2020-2023  润新知