ASP.NET 2.0, 想说爱你不容易—在ASP.NET 2.0中开发通配符映射应用程序的一些问题

     文章的题目想了好几个,比如:“在ASP.NET 2.0中开发通配符映射应用程序的一些问题”,后来考虑到为了吸引眼球:),并为了好记,选了这个有点俗的题目。
     本文主要通过分析在ASP.NET 2.0中开发ASP.NET通配符映射应用程序遇到的一些问题,来说明ASP.NET 2.0中页面编译模型的不足之处。文章中如果有不妥之处,欢迎您指出。
     这里所说的ASP.NET通配符映射应用程序是指在IIS中将所有请求转发至ASP.NET 2.0运行时处理(对于IIS 5.0,就是建立.*到aspnet_isapi.dll的映射),在程序中通过实现System.Web.IhttpHandlerFactory接口来处理所有请求,实现System.Web.IhttpHandlerFactory的类就相当于一个前端控制器。典型应用就是.Text及基于.Text开发的博客园Blog软件。
     在ASP.NET 1.1中,实现通配符映射应用程序大家可能比较清楚,主要是两点:
     1、 实现System.Web.IhttpHandlerFactory接口,在GetHandler(HttpContext context, string requestType, string url, string path)中根据请求的url,基于一些规则,找到实际访问的页面文件,然后调用PageParser.GetCompiledPageInstance对页面进行编译并生成相应的实例处理请求。这样做的好处是:你可以使用任意的url地址,不必关心是否存在对应的页面文件,而且可以方便地控制对Web服务器上资源的访问。
     2、 在web.config中加上:

<httpHandlers>
    
<add path="*" verb="*" type="Dottext.Common.UrlManager.UrlReWriteHandlerFactory,Dottext.Common" validate="false" />
</httpHandlers>

     ASP.NET 2.0中新的页面编译模型给实现通配符映射应用程序带来意想不到的问题,下面我以博客园Blog软件为例与大家一些探讨这些问题。
     在博客园Blog软件中,实现IhttpHandlerFactory接口的是Dottext.Common.UrlManager. UrlReWriteHandlerFactory,不改变在ASP.NET 1.1中实现的UrlReWriteHandlerFactory代码,直接在ASP.NET 2.0中编译并运行,当程序运行在IIS根目录下,就会在执行PageParser.GetCompiledPageInstance时出现“Object reference not set to an instance of an object”异常(运行在虚拟目录中不会出现这个问题)。这个问题是ASP.NET 2.0中的一个小Bug,之前我写的PageParser.GetCompiledPageInstance中的一个Bug及解决方法对这个问题进行了一些分析,这个问题可以通过在PageParser.GetCompiledPageInstance之前调用context.RewritePath("~/default.aspx")解决。
      接着进行访问个人Blog主页的测试,比如:http://www.cnblogs.com/dudu,访问时出现错误:

“There is no build provider registered for the extension ''. You can register one in the <compilation><buildProviders> section in machine.config or web.config. Make sure is has a BuildProviderAppliesToAttribute attribute which includes the value 'Web' or 'All'.”

     在ASP.NET 2.0中,当我们第一次访问一个页面时,必不少的两个过程是:1、页面编译 2、创建编译后的页面代码的实例。页面编译是根据所访问的url地址中的扩展名找到匹配的Build Provider对页面进行编译。这里出现的问题是由于ASP.NET 2.0运行时没找到相应的Build Provider,对http://www.cnblogs.com/dudu这样地址,由于使用了通配符映射,在ASP.NET 2.0运行时处理时,得到的扩展名是空(如果没有使用通配符映射,IIS会自动将地址改为:http://www.cnblogs.com/dudu/default.aspx)。ASP.NET 2.0在这里的设计不足之处是没有考虑这种情况,无法通过在web.config中进行相应的配置来解决这个问题。如果能提供下面的配置,这个问题就可以轻松解决:

<buildProviders >
        
<add  extension=".*" type="System.Web.Compilation.PageBuildProvider"/>
</buildProviders>

     对于这个问题,我的解决方法是在PageParser.GetCompiledPageInstance之前对url进行处理,在url中加上缺省文件,比如:default.aspx。如果你想使用其他的扩展名,比如:.html,需要在web.config中加上:

<buildProviders >
        
<add  extension=".html" type="System.Web.Compilation.PageBuildProvider"/>
</buildProviders>

     这里还有一个小bug,在上面的错误信息“Make sure is has a BuildProvider AppliesToAttribute attribute which includes the value 'Web' or 'All'.”提示需要设置AppliesToAttribute属性,实际上web.config中并不支持这样的属性,可能是正式版之前的ASP.NET 2.0支持过这个属性,后来去掉后,错误提示信息并没有修改。
     解决了上面的两个问题,原以为通配符映射应用程序可以在ASP.NET 2.0中正常运行了,我在本机上测试博客园的程序,页面能正常访问。可是今天凌晨在服务器进上将网站升级到ASP.NET 2.0之后,发现ASP.NET运行时在频繁地编译页面,CPU占用一直100%,编译了一个多小时还在编译,而且编译似乎与访问量有关,访问少的站点页面还能打开,博客园主站由于访问量大,几乎无法访问。问题出在哪?于是我从PageParser.GetCompiledPageInstance的源代码寻找线索,在BuildManager.GetCacheKeyFromVirtualPath中发现可疑之处,BuildManager是根据所请求的虚拟路径创建缓存键,然后根据这个键查找或创建页面编译后的缓存对象。当对一个页面发出请求时,BuildManager会检查缓存,先从内存中检查,如果内存中没有就从缓存文件夹(Temporary ASP.NET Files)中查找,如果找到,就直接创建该类型的实例,不进行动态编译。如果没找到,就进行页面编译工作,而且查找的依据就是根据虚拟路径创建的缓存键。对于通常的页面访问方式,这样处理不会引起问题。但对于通配符映射的情况,就会带来问题。因为通配符映射时,常见情况是不同的url地址访问的却是同一个页面文件。比如博客园中每篇文章地址不同,但访问的却是同样的页面代码,如果按照目前ASP.NET 2.0中的页面编译模型,每篇文章第一次访问都要进行编译,如果博客园中的几十万篇文章被访问,就要进行几十万编译,难怪今天博客园网站升级至ASP.NET 2.0之后,服务器一直忙于编译。
经过测试情况果然这样,当然访问地址:http://www.cnblogs.com/dudu/archive/2006/03/07/345107.html时会在Temporary ASP.NET Files中文件夹编译生成类ASP.dudu_archive_2006_03_07_345107_html,而访问其他文章地时,也根据文章地址生成另外一个类(2006年3月12日修改:对于这个问题,通过传给PageParser.GetCompiledPageInstance一个真实的虚拟地址就能解决问题,比如在博客园程序中,对于上面的地址,改为这样的代码就行了:GetCompiledPageInstance(app+"~/default.aspx", pagepath, context))。这样编译效率实在太低了!为什么要根据虚拟路径创建缓键,设计者设计时根本没考虑到通配符映射的问题,真是糟糕的设计!如果按照ASP.NET 1.1那样根据实际访问的页面文件名创建缓存键,就可以轻松地避免这个问题。ASP.NET 2.0新的页面编译模型在这里似乎是一个败笔。更糟糕的是连让开发人员弥补这个Bug的机会都没有,System.Web.Compilation.BuildManager中没有提供一个让开发人员自己设置缓存键的方法或属性。(注:创建缓存键的方法是BuildManager. GetCacheKeyFromVirtualPath(VirtualPath virtualPath, out bool keyFromVPP))。更糟糕的是,System.Web.Compilation中的很多类都是internal,很多类的方法是灰色(Reflector用灰色显示internal static或private,颜色用的不错,让人看了就灰心),想自己调用相应方法进行页面编译几乎是不可能(用反射的方法不知能否调用,还没试过,即使能调用,也要考虑性能上的损失)。难道要自己写System.Web.Compilation中那些类去处理页面编译?我宁愿选择ASP.NET 1.1,然后等ASP.NET 2.0 SP1,SP1解决不了,等SP2......希望不要等到ASP.NET 3.0。
      也许你想到了在GetHandler(HttpContext context, string requestType, string url, string path)中调用System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath来编译并创建页面的实例。这个方法我也尝试过,答案是不行,还不如PageParser.GetCompiledPageInstance,至少后者能让程序运行起来。使用BuildManager.CreateInstanceFromVirtualPath时,当访问的地址中不带扩展名时就会出现“The resource cannot be found”错误,原因是在GetVPathBuildResultInternal(VirtualPath virtualPath, bool noBuild, bool allowCrossApp, bool allowBuildInPrecompile)中调用了Util.CheckVirtualFileExists(virtualPath)对虚拟路径进行检查,检查时将虚拟路径转换为物理路径,检查当前请求的页面文件是否存在,对于通配符映射应用程序,很多地址是实际上不存在的,所以就出现“The resource cannot be found”错误。而PageParser.GetCompiledPageInstance中通过调用HostingEnvironment.AddVirtualPathToFileMapping避免了这个问题。而这个方法被
Internal保护,在代码中也无法调用。
      我觉得问题的核心是ASP.NET 2.0设计者在设计时没有考虑通配符映射这样的情况。是忽略还是另有考虑,就不得而知了。但ASP.NET 1.1能正确处理这个问题,而ASP.NET 2.0却处理不了,这里很不应该的。使用通配符映射的Web应用程序用户只能望ASP.NET 2.0心叹。最近花了很大精力想把博客园的程序迁移到ASP.NET 2.0,而结果却是无法迁移到ASP.NET 2.0,令人失望! 只能寄希望微软推出相应的补丁。
     还好,使用通配符映射的Web应用程序不是很多,这个问题影响不是很大。

     相关文章:         
        ASP.NET 2.0运行时简要分析
        ASP.NET 2.0]PageParser.GetCompiledPageInstance中的一个Bug及解决方法 
        ASP.NET 2.0中小心Profile命名冲突
        .NET, 想说爱你不容易 

posted @ 2006-03-07 22:09 dudu 阅读(6109) 评论(44)  编辑 收藏 所属分类: ASP.NET 2.0

  回复  引用  查看    
#1楼 [楼主]2006-03-07 22:34 | dudu      
在写这篇文章的时候,我想了一下写博客的好处:
1、记录想法
2、理清理路
3、加深理解
4、共享知识
5、交流学习
6、提高自己
  回复  引用  查看    
#2楼 2006-03-07 23:04 | 阿不      
有深度
  回复  引用    
#3楼 2006-03-07 23:24 | 春 [未注册用户]
总结的非常的不错。向DUDU的这种精神学习:)
  回复  引用  查看    
#4楼 2006-03-07 23:26 | 阿不      
大概看懂了意思了.那在博客园程序里不是要定义比较多的HttpHandler,并且实现UrlRewrite.
之前在2.0中使用UrlRewrite也出现了一些问题,也是与虚拟目录有关的问题.是这样的:
在同一级目录下有a.aspx,b.aspx页面都有同一菜单,在没有Url重写的情况下它的链接地址比如是:
/Security/c.aspx
而如果用URL重写访问一个b页面比如重写的地址是:b/1.aspx
这样在这个页面的链接地址就变为了:
/Security/b/c.aspx
多出了上面那个假的虚拟路径了.看来有时间要好好分析了.
  回复  引用    
#5楼 2006-03-08 00:18 | 鑫爷 [未注册用户]
不知道采用cs里使用的HttpModule实现urlrewrite,在asp.net 2.0下是否有问题
  回复  引用  查看    
#6楼 2006-03-08 08:15 | 补丁      
我用MS的urlrewriter,反倒是在asp.net1.1模式下运行会发生问题
运行在asp.net2.0下是正常的~
  回复  引用  查看    
#7楼 2006-03-08 08:49 | 阿不      
@补丁
2.0的程序在1.1下可以运行?
@鑫爷
我使用的就是cs的那种模式,在HttpModule的BeginRequest事件里重定向
  回复  引用  查看    
#8楼 2006-03-08 08:52 | [天道酬勤]      
深有同感,本来想基于asp.net2.0做目前这个项目的呢,可是最终还是放弃了,原有的一些模块和组件要升级,总是问题重重啊。
由于项目时间紧迫,不能怠懈。所以,只能先做1.1版本的啦,等做好了再慢慢改版升级吧。
  回复  引用  查看    
#9楼 2006-03-08 09:12 | THIN      
要不把地址Mapping那里把PageParser.GetCompiledPageInstance改成UrlRewrite来实现?
  回复  引用  查看    
#10楼 2006-03-08 09:16 | THIN      
我对.Text进行扩展时就用过Reflect来实现URL Mapping的一些功能。因为我的扩展使一个地址http://thinhunan.cnblogs.com这样的地址要针对不同的访问者提供两个Page instance,Web网的,提供原来的页面,WAP网的,提供手机内容页面。好在我的WAP页面使用的是自己的SDK,不需要编译.aspx页面中的内容,只要编译.aspx.cs就行
  回复  引用  查看    
#11楼 [楼主]2006-03-08 09:21 | dudu      
@阿不
不需要定义很多的HttpHandler,UrlReWriteHandlerFactory的作用就是创建HttpHandler来处理请求。
这里并没采用通常的UrlRewrite, 因为UrlRewrite是重定向到另外一个实际的虚拟地址,而博客园的程序中是直接创建一个页面的实例去处理请求。


  回复  引用    
#12楼 2006-03-08 09:41 | ff [未注册用户]
我从来就不用MS不成熟的东西,大家是被它的易用及华丽的外表骗了吧???
要反对我的暂停!!!我不回复的
  回复  引用  查看    
#13楼 2006-03-08 10:03 | THIN      
@dudu
是啊,.Text的UrlReWriteHandlerFactory类原来是用PageParser来做的,但现在asp.net2.0出现这种Bug,可能设计者本身就是希望大家用URLRewrite方法吧,而且我觉得改用Rewrite应对原有程序影响不是太大,因为Rewirte后,Request中的一些路径信息是不变的,Entry/Blog/Config等类(这里我记得不太清楚了)还是可以跟据Request分析出实际的Blog、Entry啊,不知正不正确,呵呵?
  回复  引用  查看    
#14楼 [楼主]2006-03-08 10:35 | dudu      
@THIN
谢谢你的建议! 正在研究URLRewrite。
  回复  引用    
#15楼 2006-03-08 16:34 | 黄毛 [未注册用户]
唉好久都没写程序了,用过1.1,没用过2.0的,也不知道怎么样
http://www.eysoft.cn
  回复  引用  查看    
#16楼 2006-03-08 17:37 | 天生舞男      
你的代码是如何发的,它的格式跟Visual Studio中的一样。
还有就是如何在blog里发一个钟表呢?(纯属好奇,请帮我)
我的博客为zklxj.cnblogs.com,请在我的随笔里发表一个评论的方式告诉我。谢谢!
  回复  引用    
#17楼 2006-03-09 09:24 | Activer [未注册用户]
我自认为ASP.NET水平应该已经入门, 可是看了五、六遍实在看不明白楼主到底要说明什么问题,如果想说ASP.NET2.0有BUG ,那就请用最简单的代码来重现错误,让我们水平低的人看个明白。如果想说你的ASP.NET1.1程序升级到ASP.NET2.0 遇到问题,那就贴出代码让大家讨论讨论。
asp_lha@msn.com
  回复  引用    
#18楼 2006-03-09 10:49 | dazhou [未注册用户]
UrlRewritingModule w/ Regular Expression Support for ASP.NET 2.0


http://www.urlrewriting.net/en/Config.aspx

  回复  引用    
#19楼 2006-03-10 19:38 | Activer [未注册用户]
首先申明,我替微软抱不平!!!

这片文章我居然还在Yesky里面看到了,而且是3月7日这里发出来,3月8日就在Yesky里面。如果说自己写写Blog,总结总结经验无可厚非,但是帖到yesky去误导别人就不对了。

对于你说到的PageParser.GetCompiledPageInstance,我已经在你上面那篇Blog上面写了回复。这里看到实在忍不住,还想说几句。关于IIS的问题,你想想看,对于IIS来说,当路径最后是"/"的时候,你认为是直接加个default.aspx? 没有这么简单,IIS是根据原先设置的默认文档的顺序来判断是否存在相应的文件,如果都不存在则提示错误。注意这是个处理过程,不是直接给你的"/"添加上default.aspx。如果要你要自己代替IIS做这个操作,请记得去做控制,不要什么都不做,就说是BUG。 还有微软都说了一般不要自己去搞PageParser.GetCompiledPageInstance,你就不要去搞好了 干嘛喜欢搞这个东西。

下面这几句我差点看晕过去 :
“这样编译效率实在太低了!为什么要根据虚拟路径创建缓键,设计者设计时根本没考虑到通配符映射的问题,真是糟糕的设计!如果按照ASP.NET 1.1那样根据实际访问的页面文件名创建缓存键,就可以轻松地避免这个问题。ASP.NET 2.0新的页面编译模型在这里似乎是一个败笔。更糟糕的是连让开发人员弥补这个Bug的机会都没有,...”

你以为微软吃素的? 照你这么说,微软自己用.NET开发的网站每天都要挂掉N次?
通配符映射是一种方式,你会不会用就看你自己了,你自己要控制编译,就好好的控制它。就像一辆车,你如果不会手动档 就直接开自动档,不要挂在两、三档一路向北。
  回复  引用  查看    
#20楼 [楼主]2006-03-10 21:54 | dudu      
@Activer
在你告诉我之前,我自己都不知道这篇文章被子转贴到yesky。
我本来就是自己写写Blog,也只在自己的Blog上发表过。

“IIS是根据原先设置的默认文档的顺序来判断是否存在相应的文件,如果都不存在则提示错误。注意这是个处理过程,不是直接给你的"/"添加上default.aspx。如果要你要自己代替IIS做这个操作,请记得去做控制,不要什么都不做,就说是BUG。”
我本来就不想替IIS做什么操作,正因为IIS“判断是否存在相应的文件”,才让我被迫选择使用通配符映射(也可以用UrlRewrite), 因为博客园程序中很多地址都是实际上不存在的,我只想IIS原封不动把地址传给ASP.NET运行时,然后我在程序中对地址进行分析,根据一定规则创建相应的.aspx文件的实例。而要想这样做,只能选择PageParser.GetCompiledPageInstance,PageParser.GetCompiledPageInstance也不是很特别的东西,如果不用PageParser.GetCompiledPageInstance,实际上就是用PageHandlerFactory,它们都是调用BuildManager.GetVPathBuildResultWithNoAssert或 BuildManager.GetVPathBuildResultWithAssert得到.aspx文件编译后的类型,只不过PageParser.GetCompiledPageInstance能将不存在的虚拟路径映射到实际的.aspx文件,但PageParser.GetCompiledPageInstance却在编译时没能考虑这个问题(与PageHandlerFactory调用了同样的编译代码),根据虚拟目录建立页面编译缓存。我觉得PageParser.GetCompiledPageInstance主要就是为了解决通配符映射这样的特殊处理方式,却没有解决好,让PageParser.GetCompiledPageInstance却成了没用的东西,如果微软不让用PageParser.GetCompiledPageInstance,我觉得可能就是因为这个Bug。

“照你这么说,微软自己用.NET开发的网站每天都要挂掉N次?”,这篇文章本来就是针对通配符映射这种特殊情况, 并没有说所有.NET开发的网站都存在这个问题。

“通配符映射是一种方式,你会不会用就看你自己了,你自己要控制编译,就好好的控制它。就像一辆车,你如果不会手动档 就直接开自动档,不要挂在两、三档一路向北。”
由于PageParser.GetCompiledPageInstance存在问题, 要想用这样的方法解决这个问题, 只能选择自己控制编译, 我想自己控制编译, 可微软不让,
System.Web.Compilation中很多有用的东西不能调用更不能修改,要想自己控制编译,只能自己写代码处理页面编译,一项很艰巨的任务。也就是说:如果我想开手动档, 就得自己造一辆手动档的车。
  回复  引用    
#21楼 2006-03-10 23:58 | Activer [未注册用户]
哎 你已经误入歧途了,从一开始 方向就发生错误

"我本来就不想替IIS做什么操作,正因为IIS“判断是否存在相应的文件”,才让我被迫选择使用通配符映射(也可以用UrlRewrite), 因为博客园程序中很多地址都是实际上不存在的,我只想IIS原封不动把地址传给ASP.NET运行时,然后我在程序中对地址进行分析,根据一定规则创建相应的.aspx文件的实例。"

那么你想实现的东西就是 友好的URL吧
要实现友好的URL:
1. 对于原有的参数形式的路径, 通过URL的rewrite实现友好的URL
2. 对友好URL的访问,需要通过reverse 这个URL

这无论在ASP.NET 1.1 Or 2.0 里面都无需调用PageParser之类的。
在HttpModule里面控制 然后在页面里面配合就可以了

原先还以为你调用HttpHandlerFactory要搞什么动态的加载 或者替换 HttpHandler,也就是说不需修改web.config来达到更改httpHandler

而且我也想不出 自己对ASP.NET的页面进行编译控制有什么好处。因为你的页面就是标准的.NET,没有什么自己特别的格式、语法。

ASP.NET 2.0里面对页面的编译与1.1不同,不是直接给PageParser,中间有不少过程。首先是让BuildManager来管理,让它来调用BuildProvider, 这样可以自己添加对各种文件(脚本、程序)的编译控制。夸张一点来说 也就是自己可以按自己的方式 定义自己的语言然后指定自己的编译程序来编译它

  回复  引用    
#22楼 2006-03-11 00:12 | Activer [未注册用户]
请你上网的时候 注意一下现在很多网站其实都是使用虚拟的页面路径与名称,而且很多都是.NET包括.NET2.0, 没有你想象那么多问题的
  回复  引用  查看    
#23楼 2006-03-11 09:51 | THIN      
@Activer
这里我想补充一下,可能你对.Text程序并不了解。
对于URL友好,一般的应用都是做到2005/10/23/blogentry.html这样子的路径,而.Text要处理2005/10/23/这样的路径,请注意,这个路径没有文件名,所以,必须使用通配符才能使IIS把像这样的路径都转给asp.net来处理。
至于缓存是根据用户请求的URL还是真正处理的文件更好,我的意见和DUDU是一致的,为什么?因为2005/10/12/blogentry.html和2005/10/12/blogentry.aspx和2005/10/12/blogentry.php甚至05/10/12/12345.aspx这样的路径不同,但最终的处理是一个页面文件,同一个过程,为什么要被缓存成四份呢?
技术讨论而已,不必搞得义愤填膺的吧?
  回复  引用    
#24楼 2006-03-11 10:41 | Activer [未注册用户]
@THIN
对 我对.Text程序不了解。如果有.Text的Source 我就能直接写出问题的解决方案了。

对于通配符的处理 我并没有说不好,而是说处理通配符要自己好好处理。

好像我们都没有点到问题的实质。你们始终都是说.NET2.0没有处理好 什么 什么问题,
其实是自己没有去处理,注意如果自己做好了处理 就不会有这样的问题。

友好URL怎么处理呢? 早就有人写了专门的组件来处理,你看看 根本不需要搞什么页面编译。

“至于缓存是根据用户请求的URL还是真正处理的文件更好,我的意见和DUDU是一致的,为什么?因为2005/10/12/blogentry.html 和2005/10/12/blogentry.aspx和2005/10/12/blogentry.php甚至05/10/12/12345.aspx 这样的路径不同,但最终的处理是一个页面文件,同一个过程,为什么要被缓存成四份呢? ”

这个就要问你自己了, 注意是你自己写的程序控制这个过程。

“但最终的处理是一个页面文件,同一个过程,为什么要被缓存成四份呢?”
为什么要被缓存成四份呢? 如果说是同一个,你就处理成同一个就是了。
  回复  引用  查看    
#25楼 [楼主]2006-03-11 11:05 | dudu      
@Activer
“哎 你已经误入歧途了,从一开始 方向就发生错误”,方向没有错,我需要的就是这个方向,这种方式可以很好地解决友好URL的问题,而且这种方式在ASP.NET 1.1中工作的很好,而我遇到的问题,是由于升级到ASP.NET 2.0带来的,不管怎么样, 这个问题属于ASP.NET 2.0,至少是兼容性问题。
URL ReWrite也是解决友好URL的方法之一, 但它带来了更多复杂性,需要考虑两种虚拟地址带来的问题。
“原先还以为你调用HttpHandlerFactory要搞什么动态的加载 或者替换 HttpHandler,也就是说不需修改web.config来达到更改httpHandler ”,PageParser.GetCompiledPageInstance就是动态加载HttpHandler。
“而且我也想不出 自己对ASP.NET的页面进行编译控制有什么好处”,不自己进行编译,就没法解决ASP.NET 2.0中通过虚拟路径建立缓存键的问题,不是我想要这么做,而是不得不这样做。
“ASP.NET 2.0里面对页面的编译与1.1不同,不是直接给PageParser,中间有不少过程。首先是让BuildManager来管理,让它来调用BuildProvider, 这样可以自己添加对各种文件(脚本、程序)的编译控制。”,建议你分析一下PageParser的源代码,然后你就会明白这样说是否合适。之前的回复中已经说过PageParser与PageHandlerFactory是调用同样的代码进行页面编译的。
在我们讨论时,我是一边看着PageParser的源代码,一边与你讨论,而你却凭借自己对PageParser的主观理解。

“请你上网的时候 注意一下现在很多网站其实都是使用虚拟的页面路径与名称,而且很多都是.NET包括.NET2.0, 没有你想象那么多问题的”,第三次告诉你:我说的问题是针对通配符映射这样的情况。
  回复  引用  查看    
#26楼 2006-03-11 11:09 | THIN      
@Activer
对于一个已有项目的改造不同于开发一个新项目,所以,你不要单单说为什么不这样、那样设计?如果能这样那样设计,你为什么去说国家为什么不一开始就搞市场经济,为什么不现在马上把所有的市场都开放了(我这里只是举个例子,不意政治)。
至于上面提到的缓存,请看清楚我的DUDU都是表达的PageParser对页面编译结果的缓存,不是说你自己控制的System.Web.Caching.Cache,所以,这个不是问我自己的问题。
关于自己好好处理,这里DUDU也只是提出Asp.net1.1项目迁移到2.0会遇到的问题,结大家一个借鉴,我觉得这样很好啊,也很有价值啊,比如下次我在做URL友好相关的项目时,我就会提前考虑到这个问题,做好设计,而不是碰到了问题去改设计。好好处理是要好好处理啊,未必DUDU现在就没有却解决这个问题,我上面提到用UrlRewrite代替PageParser,也是提出一个解决的思路啊,大家都是要解决问题来提高的嘛。
哎,不一定文人相轻,搞技术的都相轻,别人的东西,要不是搞出一个比.net更牛的产品来,就不是什么了不起的东西,都是不值一提浪费大家时间的狗屁东西。
@dudu
发现一个Bug,比如我在你这个Archive选了有回复通知,会把我自己的回复发邮件这来,而你(贴的主人)发的不会发邮件过来。
  回复  引用  查看    
#27楼 [楼主]2006-03-11 11:25 | dudu      
@Activer
“对于通配符的处理 我并没有说不好,而是说处理通配符要自己好好处理。”
如果要好好处理,就要重写System.Web.UI.PageParser中的代码。
如果照你这样说,对任何Bug, 微软都可以说“自己好好处理”。
对于操作系统的问题, 微软可以说“你可以自己重写一个操作系统啊”。
我再说明一下文章中讲述的问题: 正是由于ASP.NET 2.0中页面编译时,通过虚拟路径建立缓存键的问题,从而造成PageParser在通配符映射程序中无法使用。如果通过物理路径建立缓存键,就不存在这个问题。微软可以轻松地解决这个问题,而我要想解决这个问题,就要重写页面编译代码。
  回复  引用  查看    
#28楼 [楼主]2006-03-11 11:26 | dudu      
@THIN
谢谢你发现这个问题, 我会尽快解决。
  回复  引用    
#29楼 2006-03-11 23:59 | Activer [未注册用户]
@dudu

非常抱歉,这两天一直都把注意力 集中在BUG这个字眼 还有页面编译上面 没有注意到dudu已经想明白一个问题:

“[2006年3月6日修改]已经找到一种解决方法:在PageParser.GetCompiledPageInstance之前进行RewritePath处理,示例代码如下:”

我原先所说的需要自己处理 就是说的这个意思, 却没有发现dudu已经在上面的文章中做了改动。

还有上面文章中有个概念 值得商榷 虚拟路径。
像BuildManager.GetCacheKeyFromVirtualPath,这个虚拟路径是指IIS中的那个虚拟路径的意思(虚拟路径 相与对真实的路径而言)。而像2005/10/12/blogentry.html 应该算虚拟的URL,相对与真实的URL而言。

如果说很明确虚拟路径这个概念 我想你就没有上面那篇充满曲折的文章了,因为一看PageParser.GetCompiledPageInstance就知道它需要的参数是虚拟路径 而非一个虚拟的URL。
  回复  引用  查看    
#30楼 [楼主]2006-03-12 11:43 | dudu      
@Activer
说抱歉的应该是我!
昨天我发现了这个问题,对于编译时缓存键的问题,传给PageParser.GetCompiledPageInstance一个真实的虚拟路径就能解决问题。
感谢你与我认真讨论这个问题,让我学到很多东西。

在这里我向所有阅读过该文章的朋友道歉!由于我自己考虑不周, 文章的内容可能误导了您, 希望您能谅解!
PageParser.GetCompiledPageInstance中的一个Bug及解决方法中所讲到的问题依然存在。


  回复  引用    
#31楼 2006-03-12 13:12 | Activer [未注册用户]
到此为止 问题讨论的很激烈 终于大家有些共识。 讨论的目的也达到了。

dudu对问题的深入探索,不断钻研的精神实在可贵。

让偶很佩服,偶向来都是浅尝辄止。不想深入,以后也要好好学习学习,有空多写点文章与大家一起研讨技术。

-----------
题外话:既然说到VirtualPath,还要加几句。ASP.NET中对于页面或者其它文件的路径使用,一般都是依赖VirtualPath,所以需要好好理解这个VirtualPath,千万注意这个VirtualPath,它也可以不必真实映射到实际的物理路径。比如说可以映射到DataSet,呵呵放到SQL Server里面!?有意思吧。下次有空 我就写篇关于使用非物理路径VirtualPath的文章与大家一起学习学习.NET中各种新技术。
  回复  引用  查看    
#32楼 [楼主]2006-03-12 14:41 | dudu      
@Activer
欢迎你来博客园注册,与大家一起交流!
在我研究ASP.NET 2.0的源代码时,经常看到VirtualPath的身影,上面所讨论的问题中,VirtualPath是个重要角色,编译缓存键也是通过调用System.Web.VirtualPath.GetCacheKey()生成的,但VirtualPath被internal保护,不能直接调用。
对VirtualPath还不熟悉,继续研究。
期待你的文章!
  回复  引用    
#33楼 2006-03-25 00:32 | bundgrid [未注册用户]
自己写regex多好,只留一个路径省很多麻烦
  回复  引用    
#34楼 2006-08-14 15:36 | 破宝_ [未注册用户]
不知道 dudu 有没有测试过: ASP.NET 2.0 内置的 URL Mapping 功能是否存在同样的问题?
  回复  引用  查看    
#35楼 [楼主]2006-08-14 17:03 | dudu      
@破宝_
使用通配符映射主要是解决iis不会将某些地址转发给asp.net 2.0运行时。
比如:http://www.cnblogs.com/用户名,这样的地址iis由于找不到相应的文件就报错。
  回复  引用    
#36楼 2006-08-15 18:12 | 破宝_ [未注册用户]
我知道 wildcard mapping,我是说已经加了 * 映射之后,ASP.NET 2.0 内置的 URL Mapping 功能是否也存在文中所说的问题?
.Text 的 URL Rewriting 因为不是微软自己写的,Framework 升级可能会考虑不到,微软自己写的 URL Mapping 应该考虑到这些问题吧?否则就可以算 bug 了。:(
  回复  引用  查看    
#37楼 2006-10-04 23:50 | 嘻哈呵嘿      
如果在2.0的环境里运行1.1的component?
  回复  引用  查看    
#38楼 [楼主]2006-10-05 09:41 | dudu      
@嘻哈呵嘿
直接运行。
  回复  引用    
#39楼 2007-04-11 10:08 | 香水坏坏 [未注册用户]
楼主 对。NET研究还是很有深度哦 呵呵
  回复  引用  查看    
#40楼 2007-07-04 08:43 | finesite      
@dudu
挤下学习
  回复  引用  查看    
#42楼 2008-03-29 23:34 | Ylin Rain      
学到不少东西,我也正需要做1.122.0的升级,幸好是要准备在升级后再做url友好.
向dudu THIN 和Activer学习~
架吵得很火热,是非也分辨的很明白~
  回复  引用    
#43楼 2008-06-20 10:01 | 扬帆 [未注册用户]
我已经增加了
<buildProviders >
<add extension=".*" type="System.Web.Compilation.PageBuildProvider"/>
</buildProviders>
这个代码,可为什么还是提示“没有为扩展名“”注册的生成提供程序。可以在 machine.config 或 web.config 中的 <compilation><buildProviders> 节注册一个。请确保所注册的提供程序具有包含值“Web”或“All”的 BuildProviderAppliesToAttribute 属性。”这样的错误?
<compilation debug="true">
<!--解决通配符映射为伪静态FCKeditor不正常显示问题-->
<buildProviders>
<add extension=".html" type="System.Web.Compilation.PageBuildProvider"/>
</buildProviders>
<!--/////////////////////////////////////-->
</compilation>
这个代码要加在<compilation>中...我刚刚也是同样的错误,,改了以后就可以了...


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-08-06 16:09 编辑过
 
历史上的今天:

另存  打印