代码改变世界

基于CommunityServer 2.0二次开发之登录控件

2008-02-26 01:31  BAsil  阅读(2631)  评论(4编辑  收藏  举报
在CS 2.0下,使用了大量的Ajax来提高用户体验,比如AjaxPager来实现无刷新翻页,以后有时间会把AjaxPager讨论一下。
大家可能知道,在CS里面,登录是专门放到一个页面来处理的,当点击首页时,跳转到登录页面。这样做的好处是逻辑比较清楚,代码比较简单。但缺点是每次登录完后需要重新跳转到首页,增加了用户的等待时间。而我们在二次开发的过程中,很多时候希望在首页上直接有登录的区域,类似很多门户网站的操作,但是又不希望每次登录都PostBack,这样的话采用了Ajax。下面是我开发的登录控件的过程,另外由于我现在工作的环境主要还是framework 1.1,所以开发的这个登录控件也可以在1.1环境下使用。
先说一下开发的思路,由于原来CS的登录也是做成了控件的形式,通过AnonymousTemplate和LoggedInTemplate模版来配置登录时和登录后的页面,在后台完成相应的代码,也就是和Asp.net 2.0里的登录控件差不多(2.0里面简单看了看,可能比较类似)。因此改造登录控件时,我也希望延用这种方式,再把Ajax加上去。
其实在之前我也写了一个基于CS的登录控件,但是感觉不够模块化,那个控件采用了Ajax的Anthem第三方开源控件,但是正如上一篇文章CommunityServer 2.0中的Ajax和Anthem比较提到的,由于只有标识为UpdateAfterCallBack=true的控件才能够完成无刷新更新,如果页面的控件比较多,而且Asp.net控件和Anthem控件堆到一起时,代码非常的乱;另外Anthem的脚本会自动生成到aspx页中,个人感觉不便于缓存,而且如果首页上只有登录控件使用Anthem,也会生成大量的Anthem脚本文件,很是不爽。而CS2.0的Ajax,给人感觉代码比较简洁,有的时候也比较灵活。因此采用了CS 2.0的Ajax来完成,重构后的登录控件和页面耦合度更低,可以放置到各个页面而且不需要修改代码,另外可以通过Template来更改布局。
下面来看一下代码:
AjaxManager.cs这是CommunityServer中用来封装Ajax的一些代码
global.js CommunityServer中实现Ajax_CallBack的脚本
TemplateWebControl CS中用来实现皮肤调用的基类,在CS中只要有类继承此类,就需要有对应的皮肤
Login.cs 继承了TemplateWebControl,相当于一个容器
LoginView.cs 这里为了方便,直接继承了Panel,但是参考原有CS的实现,使用了ITemplate
AnonymousUserCtrlComplex.cs 匿名用户看到的内容
RegisteredUserControl.cs 登录用户看到的内容
这里着重看一下LoginView的部分代码
[PersistChildren(false), ParseChildren(true)]
    
public class LoginView : Panel,INamingContainer
    
{
        
protected override void OnInit(EventArgs e)
        
{
            
base.OnInit (e);
        
            AjaxManager.Register(
this,"Login");
        }


        
public LoginView()
        
{

        }

        [AjaxMethod(IncludeControlValuesWithCallBack
=true)]
        
public string ValidUser(string user,string password)
        
{
            
//CommunityServer.Components.User userToLogin = new CommunityServer.Components.User();
            string redirectUrl = null;
            
            
if(user=="admin" && password=="admin")
            
{
            
                FormsAuthentication.SetAuthCookie(user, 
false);
            
            }

            StringWriter stringWriter 
= new StringWriter();
            HtmlTextWriter htmlWriter 
= new HtmlTextWriter(stringWriter);            


            
this.Controls.Clear();
            
this.ChildControlsCreated=false;
            
this.Page.DataBind();
            
this.Render(htmlWriter);

            

            
return stringWriter.ToString();
        }

        
public override void DataBind()
        
{
            
this.EnsureChildControls();
            
base.DataBind ();
        }

        
protected override void CreateChildControls() 
        
{
            
this.Controls.Clear();
            
this.ChildControlsCreated=false;
            ITemplate template  
= null;

            
if(!Context.User.Identity.IsAuthenticated)
            
{
                template 
= AnonymousTemplate;
            }

            
else
            
{
                template 
= LoggedInTemplate;                
            }


            
if(template != null)
            
{
                
//basilwang 2008-02-26 没有采用原有CS增加Control的方式,而保持AnonymousTemplate的Parent为LoginView
                
//Control cntrl = new Control();
                
//template.InstantiateIn(cntrl);
                template.InstantiateIn(this);
                
//this.Controls.Add(cntrl);
            }

            
        }

        
        [
        Browsable( 
false ),
        DefaultValue( 
null ),
            Description( 
"TODO SkinTemplate Description" ),
        PersistenceMode( PersistenceMode.InnerProperty ),
        ]
        
public ITemplate AnonymousTemplate 
        
{
            
get {return _anonymousTemplate;}
            
set {_anonymousTemplate = value;}
        }

        
private ITemplate _anonymousTemplate;

        [
        Browsable( 
false ),
        DefaultValue( 
null ),
        Description( 
"TODO SkinTemplate Description" ),
        PersistenceMode( PersistenceMode.InnerProperty ),
        ]
        
public ITemplate LoggedInTemplate 
        
{
            
get {return _loggedInTemplate;}
            
set {_loggedInTemplate = value;}
        }

        
private ITemplate _loggedInTemplate;

    }

 注意AjaxManager.Register的注册时间,是在生命周期的最开始Init完成的
 另外对于CallBack的函数一定要加上[AjaxMethod(IncludeControlValuesWithCallBack=true)]
 那么对于回调生成的html,这里我向老赵学习,尽量通过framework生成规整的html,当然这里也费了我很多的时间
 由于采用了模版ITemplate,而模版在AddParsedSubObject的时候只是add到Control集合当中,注意此时并没有调用模版的CreateChildControls方法,那么什么时候这些方法会被调用呢,我开始一直认为是在Page的PreRender,但是通过Reflector发现Page的PreRenderRecursiveInternal在执行完this.EnsureChildControls()后(此时还没有递归调用他的子控件的PreRender),紧接着处理 this.OnPreRender(EventArgs.Empty);但是由于我们的Ajax方案是在PreRender时候即返回了结构,所以总是得不到Template的值。后来我使用了DataBind(建议大家在使用模版ITemplate时,别忘了DataBind这个好用的方法),因为DataBind()有一个递归EnsureChildControls()方法,可以帮助我们把所有的子控件都给创建出来,最后的事情就比较简单了,Render出来就可以了。
 另外在WebForm1.aspx页面上一定要加

{
            
//base.VerifyRenderingInServerForm(control);
        }

 防止CallBack时框架验证是否包含在服务器端Form中,这也是我觉得不爽的地方

asp.net1.1源代码附上LoginAjax.rar,asp.net 2.0下面也可以用,做一下转换即可