我尝试写了一个分层架构的.NET Web应用程序。
我要做的是用户登录后,通知页面更改显示状态。
我定义了一个类:SystemManager处理相关业务,它有一个事件: public event System.EventHandler AfterLoginEvent;当登录操作完成后就触发这个事件。
我在页面类(_Default)中加入了一个方法: On_AfterLogin,并将它注册到了SystemManager的AfterLoginEvent事件,如下:
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.IsPostBack)
            {
                ((SystemManager)Session["Manager"]).AfterLoginEvent += new EventHandler(this.On_AfterLogin);
            }        }        public void On_AfterLogin(Object sender,EventArgs e)
        {
            TextBox1.Text += "You have Logined,"+((User)Session["User"]).UserName;
        }我在单步调试时看到,程序会按照我预想的顺序执行,但最后页面显示的TextBox没有作相应改动。由于我对Page组件的运行流程没有足够的认识,所以判断不出问题所在,猜想可能是执行On_AfterLogin是在Page_Load之后,所以不能更新页面。请高手指点!

解决方案 »

  1.   

    自己解决了。
    还是对ASP.NET的理解不够深入
    问题出在:
                if (!this.IsPostBack) 
                { 
                    ((SystemManager)Session["Manager"]).AfterLoginEvent += new EventHandler(this.On_AfterLogin); 
                } 
    由于每次请求都会生成新的页面对象,而这里的方法注册是将第一次生成的Page对象的On_AfterLogin方法注册给了((SystemManager)Session["Manager"]).AfterLoginEvent。所以对于后来的Page对象,实际并未订阅AfterLoginEvent事件。
    将 if (!this.IsPostBack) 限定去掉即可。补充有分!
      

  2.   


    非常欣赏这样的客观态度。如果了解asp.net,不必谦虚。不了解asp.net,但是自己也明白问题出在哪里,钦佩。
      

  3.   

    不过你的问题也比较严重。主要是围绕着基本的《asp.net页面生命期》模型的问题。asp.net页面被处理“是一瞬间”的事!当客户端访问一个页面(包括触发回发动作)时,asp.net实例化page对象,创建这个page的设计时的控件(那些写在.aspx文件上xhtml语言标记的控件),然后依次执行init、loadViewstate、loadPostdata、触发page_load事件、触发各个控件的Changed事件、触发页面的回发事件、触发Prerender事件、saveViewState、执行Render输出html到客户端。这个过程一致性完,page对象就被“销毁”了。当用户再一次请求“同一个页面”时,服务器端建立新的page对象,尽管它与前一个是同一个(aspx文件编译生成的)类型,但是是不同的对象!你在page_load中注册这个事件处理程序,但是紧接着这个页面所在的对象就销毁了,即使方法On_AfterLogin得到执行,它也不是在新的对象执行。也就是说这个方法中如果有this,你跟踪打印它的hashcode可以发现,它不是针对当前页面对象(不是在page_load中打印的this的hashcode)。实际上,你这样做不但不能让最新的对象中的方法得到触发,可能还阻止了已经废弃的对象被GC回收,很可能让asp.net很快就因内存溢出而垮掉。当然asp.net和iis相当强劲,当应用程序内存异常时,会清理进程并重新开始新的进程,因此客户端感觉不出什么。但是你的应用程序中的session、application、cache等集合里的内容就全都初始化了。
      

  4.   


    你可以跟踪this的HashCode,看看执行时是不是最近一个page_load中的this的HashCode。如果是同一个,并且On_AfterLogin在Render方法之前执行,那么对TextBox的修改就可以在当前page的输出中体现。否则,这两个条件有一个不符合,都不能在当前page的输出中看到你要看到的文本。
      

  5.   

    上面已经说了《页面生命期》的概念,可以把Web应用程序看作一个不断刷新整个屏幕的console程序。页面是“不断刷新”的,而不是驻留在用户客户端的。这种机制让asp.net会比c/s程序响应速度慢,但是服务器端的吞吐量比c/s服务器高百倍,因为服务器端不需要在内存中保留每一个客户端的界面上的各种组件状态。虽然2、3个客户时c/s服务器明显比web服务器响应快,但是带10几个客户端就可能非常缓慢了,但是同样硬件的web服务器带1000个客户可能也响应很从容。因此,结果很简单,在asp.net上直接刷新显示就可以了,无需捕获通知。写成代码:protected void Page_PreRender(object sender, EventArgs e) 

           TextBox1.Text += "You have Logined,"+((User)Session["User"]).UserName;             } 

      

  6.   

    或者是:protected void Page_PreRender(object sender, EventArgs e)  
    {  
         if((User)Session["User"]).Loged)
           TextBox1.Text += "You have Logined,"+((User)Session["User"]).UserName;
    }  
    不过虽然你的代码错了,我其实很欣赏你的设计初衷。业务逻辑可能Notify给界面组件,很好的思路。只是只有page生命期中间的这种通知才需要。如果你了解很多UI与后台对象交互设计的好的框架,可以在asp.net中很多其它方面进行架构。例如asp.net编程中有很多“事件”代码,如果这些代码可以删除,变为在aspx或者ascx上由(美工)设计人员用xhtm声明各个控件以及与后台对象的属性绑定,就能将程序变得很干净、稳定。asp.net提供了一些数据绑定控件,但是要想彻底删除手工编码,还需要程序员开发一些紧密集合业务的数据绑定控件。如果开发复杂的页面(包扩使用到asp.net ajax的页面),不需要在页面的code-behind中写代码,或者急需要很少的十几行代码,这样的系统才是高效率的。而实现这样的东西(大量的依赖倒置设计)就需要你设计的背景。asp.net程序员许多不懂asp.net以外的其它开发工具的架构,因此对asp.net自身的业务中间件也不会开发,只会重复很简单的一些范例代码。
      

  7.   

    另外,要想对asp.net架构彻底了解,很容易。你可以下载reflector,用它打开System.Web.dll,读懂page类的ProcessRequestMain方法,或者也同时读懂control类的AddedControl方法。我在asp.net上所有能回答的问题,尽在这两方法的包容之中。
      

  8.   

    非常感谢!真没想到会有专家如此详尽的回答我的问题。
    这个“三层架构”是我想象着写出来的,后来又读了一些文章,发现自己的认识过于肤浅了。
    我是大三学生,接触.NET刚一年,现在正尝试着能够对它有更深入和系统的认识。
    下一步我会去下载您说的reflector,认真研究asp.net架构。
    再次感谢!