『注:这是比较早期一点,使用Google Docs整理自己的思路的时候写的文章,为了将整个思考的过程体现出来,贴在博客园上;由于内容比较多一些,因此,拆分成两个部分。』
DotNetNuke在新窗口中打开编辑内容
这个问题困惑了很久,现在既然已经解决了,干脆把解决的思路和过程写下来。
从本质上来说,运行中的DotNetNuke只有一个页面:就是Default.aspx这个文件(当然,在安装的时候有Install.aspx文件以 及其他几个有限的配置文件),其他的文件全部都是ascx文件——也就是.Net的“用户控件”,这有一个好处就是所有的入口统统都是这个 Default.aspx文件,比如像皮肤之类的,就好处理多了。ascx文件是通过模块配置的功能来配置的。DotNetNuke采用这种方式,使得整 个系统的编程就是编写一些用户控件而已,不需要改动整个系统的架构,所有模块级的错误都在模块中体现,不会影响到整个系统,这是非常好的一种结构。
但是我在使用DotNetNuke做开发的时候,遇到的一个很大的问题也正是这种结构引起的:由于整个系统只有一个Default.aspx文件,所以当 用户在操作的时候,只操作这一个文件,这造成的后果就是所有的内容都是在一个窗口中打开的!比如说,如果我用DotNetNuke做新闻发布平台的话,用 户能做的就是点击新闻,在同一个页面打开,然后点返回,到下一条新闻再打开。这种方式对于美国人来说是非常正常的,比如我们看CNN或者NBA或者其他的 国外网站,基本上新闻都是在当前的页面打开的,而不会在新的窗口中打开;而如果我们看一下新浪、搜狐、雅虎中国等网站的话,我们就会发现,基本上新闻内容 都是在新窗口中打开的,一般来说,中国人看新闻都会有若干个浏览器窗口同时打开,然后一个页面一个页面的看完之后再关闭掉。
为什么东西方会有这样的差异呢?我以为最开始可能是由于网络速度引起的,一开始的时候由于网络的带宽不够,所以在国内看网页的速度是非常慢的;而美国由于 身处互联网的腹地,所以可能网络的浏览速度会更快一些,所以就造成了国人一般都是同时打开若干个窗口,在看当前窗口的新闻的时候,其他的新闻在后台加载, 这样是最节约时间的;而在美国则不存在这个问题。
好了,说了这个问题之后,就引出了我的问题了:DotNetNuke的所有内容都是在一个窗口中打开的,这完全不符合中国人的阅读习惯。尤其是在五月底见 了一个客户之后,感觉就更明显了,所以,要么改变这种情况,要么就抛弃DotNetNuke,这是我一直以来非常痛苦的地方——基于DotNetNuke 编程已经两年多了,结果因为这个问题没办法进行下去,实在是太痛苦了。
当然,并不是说DNN完全不支持多窗口的模式,内容还是可以在新窗口中打开的,比如像EditUrl直接Redirect到新窗口,还是可以的;但是这样 最大的问题就是新的窗口里面包含了系统菜单、隐私说明、Banner等全部的内容,而不是仅仅只有我希望显示的模块的内容。这么做其实是等于把同一个系统 在多个窗口里面打开了,而不是一个系统的一部分(也就是只有内容部分,不包括系统菜单等系统的部分)。
关于这个问题,曾经想了这么几个解决方案:
- 自 己重新写一个aspx页面,用这个页面动态的加载DotNetNuke模块的ascx文件:这样当然也不是不行,但是问题是如果自己写一个页面的话,很多 DNN内置的变量,如UserID、ModuleID、Settings等等这些设置就完全没办法带到新的页面里面了,必须要通过URL来传递这些参数; 而且,这么做最大的问题就是已经完全破坏了DNN的整体架构的完整性,会搞得乱七八糟,这是最坏的一种做法;
- 建立一个自己的系统,和DNN进行数据交互:这是个比较疯狂的想法,我希望我的aspx驱动的系统和DNN可以共享数据,从而读取DNN的数据结构,这是在上次和用户交流过了之后,实在是没有办法的时候想的一个想法,目前这个想法已经被否定了;
- 换 平台,不用DNN:这也是一个比较疯狂的想法,如果换平台的话,之前在这个系统上做的所有的努力都将白费了,这实在是我不希望看到的。说一下,因为DNN 的有些开发人员同时在Rainbow项目组工作,所以我专门去下载了一个Rainbow的平台下来,发现和DNN不同,Rainbow是aspx页面驱动 的,而不是ascx驱动的,这就意味着如果我抛弃DNN的话,完全可以选择Rainbow平台,不过比较郁闷的是,现在Rainbow所提供的开发版本还 是过低,而且只支持VS2003和.Net1.1,我很怀疑这个平台的活跃性。就是说,如果我选择了一个没有那么多人提供模块的平台的话——也就放弃了选 择CMS作为我的系统架构的最大的优点:尽可能的使用开源的模块完成更多的功能,自己只需要专注于某一块业务,而不用管整个系统的架构和扩展性的部分;
- 复制一个新的Default.aspx文件,改写这个文件,使之只包含模块编辑的内容;
现在想起来,还是感谢Rainbow没有提供.Net 2.0和VS2005的版本,否则的话,可能我会轻易的放弃DNN,如果那样的话,我的工作量实在是太大了。
好,现在已经讲到这个地步了,我陷入了一个怪圈:我比较喜欢DNN的开发结构和开放性,这是让我感觉非常舒服的;但是我不喜欢的、也是大多数中国人都不太 喜欢的,就是所有的功能都是在一个单独的Default.aspx页面里面进行操作;老实说,我非常不喜欢,而且是要多不喜欢就有多不喜欢。那,现在怎么 办?到底要不要放弃DNN?这对我来说真的是一个大问题了。
为了实现在新窗口里面打开DNN的模块,我在网上发布了大量的求助信息,尤其是在www.DotNetNuke.com的论坛上(现在在上DNN的时候发现4.8.3版本已经发布了,我现在使用的是最新的4.8.2,看来还需要升级)。
而在Google里面,我用“DotNetNuke newwindow”、“DotNetNuke aspx”、“DotNetNuke open in New Windows”等字符串不停的搜索和找相关的资料,可惜的是,这方面的内容实在是太少了。简单的来说,老外是不太理解为什么我们一定要在新窗口中打开内 容的。
对我来说,我觉得这是一个必须要解决的问题,如果不解决这个问题的话,恐怕我总是不会安心,而且,最重要的是,客户不会满意;而且,使用DNN平台将一直会有问题。我没办法实现我的DNN做更多的事情的想法。
怎么办?
所幸的是,在不断的搜索和阅读英文资料和论坛的同时,还是学到了一些东西,比如像以下的几个东西,就是比较不错的:
- 解 释DNN的URL转向原理:DNN的自己有一个专门的HttpModule模块,这个模块是用来解析整个网站的页面的,举一个例子,比如说像 http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryID/453 /Default.aspx这样一个URL,如果能够清楚的理解了这个URL的话,就对DNN的Url处理机制有一个比较清晰的了解了。一般的来说,想这 样的一个URL,我们一般是在www.dotnetnuke.com这个网站下面有一个Community的目录,在这个目录的下面有一个Blogs的子 目录,然后下面有tabid/825/EntryID/453等这样的子目录结构,然后在这个目录下面,有一个Default.aspx文件,这个文件是 一个独立的aspx文件,和根目录下的Default.aspx是完全不同的两个文件。用这种方式来理解一般的网站结构是完全没有问题的,但是如果用来理 解DotNetNuke的话,就完全错了。如果我们能够到这个网站的根目录下面去看一下的话,就会发现,上面的目录结构是根本不存在的,更不要说在最底层 的目录中还有一个Default.aspx文件了,完全没有!这是怎么回事呢?原来,DotNetNuke核心小组在开发DotNetNuke的同时,注 意到一件事情,就是如果页面的地址中包含太多参数的话,会严重的影响Google等搜索引擎的收录,比如像 http://www.dotnetnuke.com/default.aspx?tabid=825&entryid=453等这种样子的 URL,对Google等搜索引擎是十分“不友好”的,所以,为了让搜索引擎更好的收录地址,DotNetNuke自己开发了一个HttpModule, 用这个模块专门处理URL,把页面的参数,转化为目录的形式,例如/tabid/825实际上对应的是?tabid=825这样的参数形 式,DotNetNuke在后台自动将参数进行转换,从而使得系统可以识别;
- SiteUrls.config文 件:为了更加灵活的解释各种各样可能的URL,DotNetNuke在安装程序的根目录下放置了一个SiteUrls.config文件,该文件是用来配 置遇到各种类型的路径的时候,系统如何去解释的,举一个例子,在标准的DNN安装版本中,比如我们访问刚才的地址 http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryID/453 /Default.aspx,这个时候,如果我们最后面的Default.aspx改成test.aspx,会发生什么情况呢?有一般的网站使用常识的都 会知道,我们任意输入的一个文件名,在服务器上一般都不会有的,所以一般都会显示“无法显示该页”的错误。但是,由于DNN已经通过HttpModule 进行了Url的转向管理,所以我们在安装了DNN之后可以测试一下,任意输入一个文件名,仍然会显示当前正确的网址,也就是说,输入任何的一个文件都可以 访问到该模块的正确网页。这就是SiteUrls.config文件在起作用了。在SiteUrls.config文件中,包括 有<RewriterRule>节点,在该节点中定义了Url访问的规则,通过这些规则来控制Url是如何进行转向的。我们可以发现,最后一 条规则是[^?]*/TabId/(\d+)(.*),转向到“~/Default.aspx?TabId=$1”,也就是说,只要Url中含有 TabId的页面,都会转向到该页面指定的Default.aspx这个页面,这就是HttpModule的转向定义功能;
- 皮肤的概念:由于之前的项目需要对皮肤进行定义,因此现在对DNN的皮肤相对来说已经比较熟悉了。DNN所有加载的几大块区域,都是在皮肤里面加载的,通过皮肤来控制页面拥有的板块以及整体的风格;而每个模块的风格则通过容器的皮肤来指定。
有了以上的几个概念,我想要完成的事情——也就是在一个新窗口打开编辑页面——而且仅仅是编辑页面,不包括页面的其他任何部分,经过很长时间的冥思苦想,终于有了一个眉目:就是在不对现有的系统做任何框架性修改的前提之下,可以完成这个功能。
由于DNN所有的页面加载部分是在皮肤文件里面完成的,所以第一个测试就是,如果皮肤文件是最简单的,那么是不是可以达到编辑页面只有编辑内容,而没有任 何其他要素的要求呢?于是修改了DNN的缺省皮肤,在皮肤文件中,只保留了TopPane、LeftPane、CenterPane、RightPane 和BottomPane的定义,整个模块就只包含这几个部分,而没有DNNMenu和其他的部分,经过测试,这样是可以的,完全可以做到在编辑的时候只有 内容,而没有其他任何的页面元素——实际上,不仅仅是编辑的时候,而是所有的页面都是只包含以上几个Pane的内容,不包含DNNMenu、 Privacy等元素,但是我们想要的并不是全部都去掉——如果全部都去掉的话,整个系统也就没有意义了,所以,必须要在一般性页面上保留所有的内容,而 仅仅在编辑的时候加载最简单的页面——这就是要求。在这种情况之下,一般的页面加载完整的皮肤,而编辑页面加载最简单的皮肤,这个时候,仅有一个 Default.aspx文件就明显是不够的了,所以,必须要增加新的页面,也就是我的Edit.aspx页面。
我的思路到现在完全清楚了:正常的情况下,DotNetNuke只包含一个页面用于处理所有的需求,也就是Default.aspx页面;但是,为了实现 一般性页面显示完整、编辑页面显示最简单的内容的要求,我需要增加一个页面,这个页面在启动的时候,加载最简洁的皮肤,并且加载模块的编辑内容,这样,就 可以确保可以达到我的要求;而同时,增加的页面是在DotNetNuke的框架考虑范围之内的,并不是任意乱加页面破坏系统的框架,所以增加的页面是完全 符合DotNetNuke的框架要求的,增加的页面不会给模块的开发带来任何一点点困扰和负担,正常的模块开发仍然按照DotNetNuke的标准版本进 行。
OK,有了这个思路,我们再来看一下Default.aspx文件,所有的事情就十分简单了。
在Default.aspx.vb文件中有一个LoadSkin的方法,这个方法是加载系统指定的皮肤的,简单来说,当管理员更换了皮肤之 后,Default.aspx知道管理员指定了哪一个皮肤,然后到相应的文件夹下面(Portals/0/_default/skinname/)找到相 应的皮肤文件,一般是skin.ascx,也可能是其他的文件,总之,系统会自动识别。我们只需要对这一段进行修改就可以了。
复制一份Default.aspx文件,然后将之改名,改为我们希望的名字,如NewDefault.aspx等,随便,都可以。然后,在加载皮肤的时 候,我们耍一个花枪,当找到某个目录的时候,我们不是加载缺省的皮肤文件,如Skin.ascx,而是加载Skin_mini.ascx文件,这个文件是 由我们自己制作的,只包含TopPane等五块核心区域,而没有其他的任何东西。这样当我们新的NewDefault.aspx文件加载这个皮肤文件的时 候,就是光秃秃的只有我们希望的编辑区域了。
做完之后,访问一下我们的NewDefault.aspx,如
http://localhost /DNN482/tabid/33/mid/382/NewDefault.aspx,我们看一下会发生什么事情,奇怪的是,系统仍然转向到了 Default.aspx文件,就方佛我们的NewDefault.aspx文件不存在似的。没错,对于当前的网站来说,无论我们在根目录下增加多少个 aspx文件,系统都会认为这个文件是不存在的!所以,我们必须要了解SiteUrls.config文件的运作原理,并且修改这个文件,以便允许我们的 文件可以执行。
这个先留一下。