人无信不立/2008-04-26 22:30

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中取出资源。
首先把类的代码贴出来,我想可能许多人应该和我一样,喜欢直接先看代码:)
DllVirtualPathProvider
重点有以下几个:
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方法:
GetCacheDependency
这里改成直接改成当前网站的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);



 
posted @ 2008-04-19 20:17 永春 阅读(3543) 评论(29)  编辑 收藏 网摘 所属分类: .Net

  回复  引用  查看    
#1楼2008-04-19 20:25 | Stanley.Luo      
不错, 沙发一下
  回复  引用  查看    
#2楼2008-04-19 20:29 | 生鱼片      
MOSS中就是这个机制
  回复  引用  查看    
#3楼[楼主]2008-04-19 20:30 | 永春      
@生鱼片
对,MOSS中就是放到数据库中的。

  回复  引用  查看    
#4楼2008-04-19 20:35 | 生鱼片      
@永春
是啊,MOSS中的site page定制后就存到DB中了

  回复  引用  查看    
#5楼2008-04-19 20:35 | 菜菜灰      
效率怎么样~~
  回复  引用  查看    
#6楼[楼主]2008-04-19 20:37 | 永春      
@菜菜灰
我试了,效率不错,特别是GetCacheDependency方法,原来返回null效率很慢,改过之后,效率很好的

  回复  引用  查看    
#7楼2008-04-19 22:29 | 侯垒      
很不错,不过我的右击->没有属性,应该是没有安装sp1.
  回复  引用  查看    
#8楼2008-04-20 00:58 | 远航      
正在使用中...
  回复  引用    
#9楼2008-04-20 05:09 | <Null>[未注册用户]
ascx可以直接 pre-compile 成 dll 部署到生产环境里去吧,不用这么麻烦。
  回复  引用  查看    
#10楼2008-04-20 09:35 | 李战      
http://www.cnblogs.com/Emoticons/qface/055243188.gif" alt="" />好!这个对俺有用!
好!谢谢

  回复  引用  查看    
#11楼2008-04-20 11:53 | Leepy      
请问为什么我在页面浏览上显示 虚拟路径“/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample1.ascx”映射到另一个应用程序,这是不允许的。
在IIS上需要做些什么设置吗?

  回复  引用  查看    
#12楼2008-04-20 12:10 | 曾哲      
@永春

怎么修改的啊 ?

  回复  引用  查看    
#13楼2008-04-20 12:11 | 曾哲      
我试了,效率不错,特别是GetCacheDependency方法,原来返回null效率很慢,改过之后,效率很好的


这里修改了什么?

  回复  引用  查看    
#14楼2008-04-20 12:42 | 曲滨*銘龘鶽      
关于 VirtualPathProvider 的确不错
不过对网站形式的 ascx在 asp.net的应用没啥意义;
因为网站形式的发布完本身就是编译过的没有 ascx 这个文件根本;

  回复  引用  查看    
#15楼2008-04-21 09:01 | 王孟军!      
好东西
  回复  引用  查看    
#16楼[楼主]2008-04-21 09:04 | 永春      
@侯垒
在文件上右键应该都有属性的

  回复  引用  查看    
#17楼[楼主]2008-04-21 09:15 | 永春      
@&lt;Null&gt;
预编译的话很麻烦的,而且不方便使用

  回复  引用  查看    
#18楼[楼主]2008-04-21 09:16 | 永春      
@Leepy
你的报错信息是什么?global中注册了吗?

  回复  引用  查看    
#19楼[楼主]2008-04-21 09:17 | 永春      
@曾哲
修改之后就是不返回null了,修改后的代码可以看我文章中的代码

  回复  引用  查看    
#20楼[楼主]2008-04-21 09:21 | 永春      
@曲滨*銘龘鶽
发布后是有ascx文件的
而且编译成一个dll后可以方便给其他项目调用的

  回复  引用  查看    
#21楼2008-04-21 14:59 | Leepy      
我是创建一个“MyWebApplication”的asp.net应用程序,建立了两个用户控件,设置了嵌入的资源,生成了dll文件;然后新建了一个网站,把该dll文件放入MyUserControl文件夹中,另外按照您的要求,在网站的global中注册了,可是出来的错误信息就是 虚拟路径“/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample1.ascx”映射到另一个应用程序,这是不允许的。

  回复  引用  查看    
#22楼[楼主]2008-04-21 15:42 | 永春      
@Leepy
应该把该dll文件放入网站的bin目录下
在网站下建立目录:MyUserControl/MyWebApplication.dll

你再试试看?

  回复  引用  查看    
#23楼2008-04-21 16:52 | Leepy      
不是很明白,目录是不允许使用“/”符号的啊
  回复  引用  查看    
#24楼[楼主]2008-04-21 17:07 | 永春      
@Leepy
我可能没说清楚-_-
是在网站下建立目录:MyUserControl,然后再在MyUserControl下建立子目录:MyWebApplication.dll

  回复  引用  查看    
#25楼2008-04-21 17:34 | Leepy      
还是不可以,你有MSN吗?我加您下吧,
  回复  引用  查看    
#26楼[楼主]2008-04-21 17:41 | 永春      
@Leepy
给你发消息了




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1161431




相关文章:

相关链接: