DbEntry 开发实践:Wiki 系统(六)

经过前面一系列的代码编写,我们有了一个可以工作的Wiki系统,现在我们先来给它进行一点儿美化。

  我想象中的布局方式是,顶部是banner,导航栏,编辑、历史等链接,中间是Wiki或者FckEditor,下面是底边栏,显示一些提示信息和版权信息。这可以使用frame、iframe自己编码实现,也可以利用一些工具,我选择使用JQuery和它的插件JQuery Layout。

  在VisualWiki里创建scripts目录,加入jquery和jquery layout,我用的版本是1.2.6。另外,加入jquery-1.2.6-vsdoc.js的话,在Visual Studio里也可以进行JQuery的智能提示。再创建一个styles目录,把BasicStyle.css复制进去,我们还需要多一些css支持,也可以添加到这个css文件中。创建一个images,放入一个banner.jpg文件等等。

  JQuery Layout的写法基本上是定义一些特定class的div,然后把不同的内容,放入不同的div里,然后在script里初始化一下它,就可以了。所以,对于Show或者Edit页面,基本不用修改,只要修改Main.master就可以了,另外,考虑到我们要加入登录功能,我想用master页来进行鉴权工作,分离出一个新的master页也许更好些,Main.master负责鉴权和部分布局(manage部分也需要banner),而Wiki.master负责Wiki的布局,在Main.master里加入对于css和js的链接,并调用jquery layout进行初始化,它还会调用Wiki.master里的resetLayout以完成Wiki页的layout工作:

代码
<%@ Master Language="C#" Inherits="Lephone.Web.SmartMasterPageBase" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    
<title></title>
    
<link type="text/css" href="styles/BasicStyle.css" rel="stylesheet" />
    
<script type="text/javascript" src="scripts/jquery-1.2.6.js"></script>
    
<script type="text/javascript" src="scripts/jquery.layout.js"></script>
    
<script type="text/javascript">
        
function resetMainLayout() {
            $(
'form').layout({ slidable: false, resizable: false, closable: false,
                spacing_open: 
0, north__size: 52, center__paneSelector: "#mainContent"
            });
            
if (resetLayout)
                resetLayout();
        }
        $(document).ready(
function() { resetMainLayout(); });
        $(window).resize(
function() { resetMainLayout(); }); // for resize bug with form
    </script>
    
<asp:ContentPlaceHolder id="head" runat="server">
    
</asp:ContentPlaceHolder>
</head>
<body>
    
<form id="form1" runat="server">
        
<div class="ui-layout-north banner">
        
</div>
        
        
<div class="ui-layout-center">
        
</div>

        
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
        
</asp:ContentPlaceHolder>
    
</form>
</body>
</html>

  Wiki.master里增加的也基本上是一些div和一个resetLayout函数:

代码
<%@ Master Language="C#" MasterPageFile="~/Main.master"  Inherits="Lephone.Web.SmartMasterPageBase" %>

<script runat="server">
    [HttpParameter] public string title;
    [HttpParameter(AllowEmpty 
= true)] public string path;

    protected 
void Page_Load(object sender, EventArgs e)
    {
        NavigationBar.Text 
= CommonHelper.GetNavigationBar(title, path);
        
var pageName = Request.Url.Segments[2];
        CommonHelper.SetLink(Edit, pageName, 
"Edit.aspx", title, path);
        CommonHelper.SetLink(History, pageName, 
"History.aspx", title, path);
    }
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    
<script type="text/javascript">
        
function resetLayout() {
            $(
'#mainContent').layout({ slidable: false, resizable: false, closable: false, spacing_open: 0, north__maxSize: 31, south__maxSize: 27 });
        }
    
</script>
    
<asp:ContentPlaceHolder id="head" runat="server">
    
</asp:ContentPlaceHolder>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<div id="mainContent">
    
<div class="ui-layout-north header">
        
<div id="navigator">
            
<asp:Label ID="NavigationBar" runat="server" Text="Home"></asp:Label>
        
</div>
        
<div id="oprator">
            
<asp:HyperLink ID="Edit" runat="server">Edit</asp:HyperLink> |
            
<asp:HyperLink ID="History" runat="server">History</asp:HyperLink>
        
</div>
    
</div>

    
<div class="ui-layout-center body">
        
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
        
</asp:ContentPlaceHolder>
    
</div>

    
<div class="ui-layout-south footer">
    
<biz:NoticeLabel ID="msg" runat="server" SingleLine="true" />
    
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    copyright 
&copy Lephone Studio
    
</div>
</div>
</asp:Content>


  上一张运行截图:



  现在,我们开始设计登录及成员管理功能。DbEntry也支持ASP.Net的MemberShip功能,并且使之可以支持所有DbEntry支持的数据库,不过这里,我们并不使用MemberShip,而是自己设计一个用户表SysUser,其中,password应该是hash的,所以CommonHelper中需要增加一个生成password的函数:

代码
private static readonly SHA512 Hash = SHA512.Create();

public static string GetHashedPassword(string password)
{
    var bytes 
= Hash.ComputeHash(Encoding.UTF8.GetBytes(password));
    var ret 
= Base32StringCoding.Decode(bytes);
    
return ret;
}

  SysUser如下:

代码
namespace VisualWiki.Models
{
    
public enum UserRole
    {
        Administrator,
        User,
    }

    
public abstract class SysUser : LinqObjectModel<SysUser>
    {
        [Length(
150), Index(UNIQUE = true)]
        
public abstract string Name { getset; }

        [Length(
1128)]
        
public abstract string Password { getset; }

        
public abstract UserRole Role { getset; }

        
public SysUser Init(string name, string password, UserRole role)
        {
            Name 
= name;
            Password 
= CommonHelper.GetHashedPassword(password);
            Role 
= role;
            
return this;
        }

        
public static SysUser GetUserForLogin(string name, string password)
        {
            var pass 
= CommonHelper.GetHashedPassword(password);
            var u 
= FindOne(p => p.Name == name);
            
if (u != null && u.Password != pass)
            {
                
return null;
            }
            
return u;
        }
    }
}

  然后在DataSources里增加SysUserDataSource,同样也不需要有任何代码。然后增加一个使用Main.master的Manage.master页,其中有两个链接,User List和New User。在Main.master的banner上,增加一个Label,显示一下欢迎信息。

  在VisualWiki项目下,增加使用Manage.master的UserList.aspx,向其中添加GridView,SysUserDataSource,并设置GridView的DataSource为SysUserDataSource,添加Role列(这是GridView的bug,不能识别enum列),另外,添加一个HyperLinkField,用来提供一个编辑链接:

<asp:HyperLinkField Text="Edit" DataNavigateUrlFields="Id" DataNavigateUrlFormatString="~/UserEdit.aspx?ID={0}" />

  UserList.aspx页就开发完成了。UserEdit.aspx页也和DbEntry.Net主页介绍的编辑页编写流程类似,使用TemplateBuilder可以在几分钟之内完成。这里,我们对于Edit方式,设置Name控件为不可修改,另外,有一个和普通的编辑页面不同的需求,就是Password需要是hash的,所以,在SysUserDataSource 的OnObjectUpdating和OnObjectInserting事件中处理:

代码
protected void SysUserDataSource1_OnObjectUpdating(SysUser o)
{
    o.Password 
= CommonHelper.GetHashedPassword(o.Password);
}

protected void SysUserDataSource1_OnObjectInserting(SysUser o)
{
    o.Password 
= CommonHelper.GetHashedPassword(o.Password);
}

  这样,用户管理页面基本开发完毕。我们再增加一个Login页面,这个Login页面不使用任何母板页,在Page_Load里,如果不是PostBack,则进行SignOut操作,而点击SignIn按钮,则调用SysUser.GetUserForLogin验证登录合法性。登录成功,则转向Default.aspx页,而Default.aspx也需要修改一下,根据登录用户的不同类型,重定向到不同的页面:

代码
protected void Page_Load(object sender, EventArgs e)
{
    
if (this.GetLoginUser().Role == UserRole.Administrator)
    {
        Response.Redirect(
"UserList.aspx");
    }
    
else
    {
        Response.Redirect(
new UrlBuilder("Show.aspx").Add(Const.TitleName, Const.HomeName).ToString());
    }
}

  这里,我在WebUIExtends里建立了几个扩展方法,用来协助用户登录操作,比如GetLoginUser、SetLoginUser等等:

public static SysUser GetLoginUser(this Page p)
{
    
return (SysUser)p.Session["LoginUser"];
}

public static void SetLoginUser(this Page p, SysUser u)
{
    p.Session[
"LoginUser"= u;
}

  然后修改Main.master,重载OnInit函数(之所以不是写在Page_Load中,在于ASP.Net在母板页、普通页及控件中奇怪的事件加载顺序),进行用户登录与否的判断,修改Manage.master和Wiki.master,在Page_Load函数里判断登录对象类型,如果类型错误,则返回Login页面,另外,修改web.config中的authentication节,定义登录页面和缺省页面:

<authentication mode="Forms">
  
<forms name=".ADUAUTH" loginUrl="Login.aspx" defaultUrl="Default.aspx" protection="None"/>
</authentication>

  现在,运行程序,我们会被重导向到Login页面,不过,我们还没有可以用来登录的用户,让我们修改一下Global.asax,以便为我们增加一个管理员:

void Application_Start(object sender, EventArgs e)
{
    
if(SysUser.GetCount(null== 0)
    {
        SysUser.New.Init(
"tom""123", UserRole.Administrator).Save();
    }
}

  现在,运行程序,会被带入Login页面,输入tom/123登录,进入管理界面,点击New User链接以增加一个Wiki用户jerry/456,点击Logout退出登录,再使用jerry登录,就可以进入Wiki浏览、编辑界面了。

  这样,用户管理界面也基本开发完毕,本来也以为这应该是这个系列文章的最后,不过,我们还需要处理其它一些细节,所以,提交代码、未完待续……

  目前的代码:VisualWiki6.7z
posted @ 2009-12-06 21:03  梁利锋  阅读(1418)  评论(2编辑  收藏  举报