另类的动态加载用户控件

   最新更新:原本在看到此方案的时候觉的想到这方案的朋友特别高深,后来本人把本文写出来想和大家分享下,才知道这个就是Dottext方案中的一个模块而已.真是汗啊,嫌自己见识太浅。既然写了就当复习了一次Dottext.。这还是我第一次听说Dottext.
  
   在BS架构这块,我们平时建一个网站,通常是创建一个WebSite网站,或者是创建一个WebApplication.然后在WEB项目里面建立相应的aspx文件,以及用户控件,自定义控件等等.但是做为一个新加入此项目的你要去修改里面的
某一个功能模板,那么我一般的程序是这样的:

    第一:根据新的需求,在项目找到相关页面,例如对应的页面URL为index.aspx.此时可以对原页面做最初的了解.
    第二:分析代码.
    第三:根据新的需求来修改代码.

    我想这也是一般朋友的思维模式吧.可是这样的流程并不是统一不变的,至于如何变化,我先想和园友们讨论一下如下的需求大家是如何实现的?

    网站可能有多个版本,例如最起码的中英日版,各版本的内容呈现风格上也略有不同.

    本人列举三个本人想到的做法:

    第一种方法:每个版本单独建一个站点.具体要求具体实现.这种做法的缺点是维护困难,成本高.

    第二种方法:建一个站点,为每个版本的同一个功能页面分别创建单独的页面.例如一个显示新闻的页面,分别为:中文新闻.aspx,英文新闻.aspx等.这种方法的缺点同上,只不过稍微会容易点.

    第三种方法:建一个站点,一个功能就建一个页面,但为不同版本创建不同的用户控件,根据相应的参数为动态加载控件.这种做法是最优的.(个人认为)这做做法的缺点是程序的耦合度太强,如果是要增加一个版本,那么就要修改功能页面.

    其实上面的第三种方法一般来说是可以解决问题的.后来在新的项目中发现了httpHandler的应用,可以自定义的捕捉到http请求.发现了一个全新的解决方案.

    IHttpHandlerFactory在.net中算是用处比较多的。它能够在Hander对象生成前对当前页面的Hander进行预处理。一般我们如果是做URL重写的话,也会用到httphandler,现在可以利用它来实现我上面的需求.

    网站呢,就建一个页面webform2.aspx.在这个页面中根据请求的URL来动态加载用户控件.而这个动态加载程序并不是写在webform2中的pageload事件中.而是写的页面的AddParsedSubObject事件中.当用户访问别外一个页面,例如一个搜索页search.aspx,此时站中并不实际存在这个页面.而是利用httphandler来捕获这个HTTP请求,定向于已经实际存在的webform2.aspx页面,在webform2.aspx页面中的AddParsedSubObject事件中完成搜索控件的加载.

    第一:如何来自定义的来捕获HTTP请求呢?

   1:建立一个实现了接口IHttpHandlerFactory的类.
      IHttpHandlerFactory 类型公开了以下成员。
方法 :
  GetHandler  返回实现 IHttpHandler 接口的类的实例。
  ReleaseHandler  使工厂可以重用现有的处理程序实例。
Code

    2:配置WEB.CONFIG
<httpHandlers>
   <add verb="*" path="/*.aspx" type="WebApplication_Test.WebPageHandlerFactory, WebApplication_Test"/>
  </httpHandlers>
    参数简单说明:
        path:要捕获的文件路径.
        type:WebApplication_Test.WebPageHandlerFactory :实现了接口IHttpHandlerFactory的类
        WebApplication_Test:WEB站的命名空间

     这样就可以捕获HTTP请求了,例如请求index2.aspx,站点中并不存在,但是当你访问时程序并不会报错,而是会实际转向到webform2.aspx.此时用户看到的还是index2.aspx.

     第二:如何实现根据URL来动态加载用户控件呢?并不是在页面用if条件判断.这里我们要提一下HtmlContainerControl.

     HtmlContainerControl:
          用作映射到需要具有开始标记和结束标记的 HTML 元素的 HTML 服务器控件的抽象基类。

     我们通常在一个页面动态加载控件,都是在页面中放一个pannel,此pannel一般放在form中,这样用户控件中的服务器控件就可以正常运行了.然后把要加载的控件加入到pannel中即可.为此我们可以自定义一个继承HtmlContainerControl的服务器控件来充当pannel容器.

     总的实现过程如下:
     1:建立的容器页:WebForm2.aspx,站点中只存在这一个页面,其它的页面请求都是通过它运行的.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs"  Inherits="WebApplication_Test.WebForm2" %>
<%@ Register TagPrefix="ccWebUI" Namespace="Common.UI" Assembly="Common.UI"  %>
<ccWebUI:masterpagecontrol id="MPContainer" runat="server"></ccWebUI:masterpagecontrol>

      页面cs代码
      //装入模板  

Code


     AddParsedSubObject:
       通知服务器控件某个元素(XML 或 HTML)已经过语法分析,并将该元素添加到服务器控件的 ControlCollection 对象。通过这个事件可以对页面的所有控件进行分析并能够进一步操作页面加载过程,例如本文提出的根据URL来动态加载用户控件.

     AppSettingPage:页面配置文件,它实现了根据用户请求的URL来指定应该加载哪一个控件.
 
     
Code

     类:TemplateConfig.cs 它根据URL来与TemplateConfig.xml相匹配,返回要加载控件的路径,这样做就可以实现加载控件与页面逻辑的解耦了,只要在配置文件中配置好URL与控件路径的对应关系就行。
    
     
Code

        页面配置文件TemplateConfig.xml:一个URL对应一个用户控件。用户可以把用户实际访问的页面URL与相对应的用户控件对应起来,这样在httphander处理的时候就能够找到正确的信息加载了.他的好处是修改功能不用修改程序,只要配置就可以.例如此时有另一个页面中出现了一个变种页面,就是增加了一个功能,此时只要写好了相应的用户控件,然后在此配置文件中加入配置信息<page pageName="新的页面" target-page="新的用户控件路径"></page >,并不需要修改程序.
       
Code
  
     基类:BasePage.上面的webform2中并没有出现传统的html标记,一个页面要想正常显示相应的HTML标记是必不可少的.
     
Code

    masterpagecontrol:一个自定义容器的服务器控件:
   
Code

     为此就以本文前面的需求来说,例如有一个新闻页面,他有三个版本.我们只需求建好三个用户控件,分别实现读取新闻功能.配置文件如下,此后用户就可以通过访问中文新闻.aspx来访问中文版的了,其它的同理.如果此时多了一个韩文版的,只要建好一个韩文新闻.ascx,加上配置文件就行.

Code

     本人写的不太合理,可能大部分朋友有可能看不懂。为此特将本人的DEMO提供下载,希望对这方面感兴趣的朋友会有所帮助。此种方案并非最优,要看不同项目的具体需求了,关键的是能够解决问题.本文旨在和园友们互相讨论,如有不足的地方请指教. 程序下载
posted on 2008-07-06 17:06  min.jiang  阅读(4480)  评论(10编辑  收藏  举报