Riverside网上论坛

分享于 

30分钟阅读

Web开发

  繁體

Riverside因特网论坛

<-------------------------------步骤 3 ---------------------------> <--添加文章文本。 请使用简单格式(

,

等) -->

介绍

本文描述了一组 ASP.NET 自定义控件,可以快速且容易地将论坛添加到任何网页。 论坛代码最初使用VB脚本和ASP页面编写,其中的一个主要目标是模仿CodeProject论坛的外观和感觉。 随后,论坛被用 C# 作为 ASP.NET 定制控件编写。 当论坛在树视图模式下查看时,外观和感觉非常类似于to论坛。 然而,在平面视图中,论坛外观看起来更像是在 http://www.asp.net/中找到的论坛。

这里提供的河南网论坛是一组更大的ASP.NET 定制控件,组成了河南网络 WebSolution。 完整的WebSolution以及包含论坛,提供管理文件夹。文档和一般web内容的控制。 最后希望所有这些代码都将提交到 CodeProject。

入门

  • RiversideInternetForums.zip 解压缩到目录 C:RiversideInternetForums
  • 使用 IIS,添加具有别名RiversideInternetForums的新虚拟目录,并指定包含内容的目录的路径 C:RiversideInternetForums
  • 从IIS中,授予对头像目录的写访问权限。
  • 打开 WebSolution.zip 以提取文件 WebSolution.sql
  • WebSolution.sql 发送到 SQL Server 以创建数据库 RiversideInternetForums。表 WS_WebsWS_UsersWS_ThreadsWS_Posts。关联索引和存储过程。
  • 编辑 C:RiversideInternetForumsWeb.config 因此应用程序设置"websolutionconnectionstring"是RiversideInternetForums数据库的有效连接字符串。
  • 你将必须向RiversideInternetForums数据库中添加一个新用户,该数据库角色中允许使用该用户: public 和db_owner当使用受信任的连接时,这里用户的NAME 将采用表单 <COMPUTER NAME>ASPNET
  • 启动浏览器并打开虚拟目录 RiversideInternetForums ( 例如 http://localhost/riversideinternetforums/ ) 以查看结果。 你应该有一个空的论坛。
  • 单击 Join 设置新用户。 然后开始投递 !

一个警告:虽然本文中没有描述,但是 from WebSolution设计用来支持单个数据库/代码库安装。 多个网站通过将web标识符( WebID ) 与每个网站的( WebDomain ) 相关联来支持。 这些关联存储在数据库 table WS_Webs 中。 默认情况下,WebSolution.sql 脚本为网站"localhost"插入网页标识符 1. 但是,如果你的IIS服务器没有被"localhost"引用,那么你需要更改值"localhost"来反映你的IIS服务器的NAME。 和其他网址一样,你也可以使用 http://www.riversideinternet.com/ 来访问网站,因此必须将一行插入到 WS_Webs 中,并将 WebDomain 等于 1,并将它的设置为HTTP请求的主机名。 WS_Webs.Folder 可以为空。

首先要注意的是,向网页添加论坛是多么简单。 所需的是以下两行( 查看 default.aspx ):

<%@RegisterTagPrefix="WS"Namespace="RiversideInternet.WebSolution"Assembly="RiversideInternet.WebSolution"%><WS:ForumForumID="1"Runat="server"id="_forum"/>

default.aspx的顶部为 Join,登录,我的设置和注销提供链接的控件是使用下面的代码创建的:

<WS:LoginControlBorderStyle="None"Runat="server"id="_loginControl"/>

某些操作,如启动新线程或者发布答复,需要用户登录。 如果用户当前未登录,执行其中一个操作将导致用户被重定向到登录页。 重定向到的页面由在 Web.config 中找到的应用程序设置"websolutionusermanagementurl"确定。 这里页面应包含用户管理控制:

<WS:UserManagementRunat="server"id="_userManagement"/>

论坛使用"窗体"身份验证来确定用户是否已经登录或者关闭。 因此,在 Web.config 中找到的身份验证模式应该设置为"窗体"。

Web.config 中发现的其他应用程序设置是"websolutionavatarsurl",它是可以在其中找到头像的网络地址。 在提供的Web.config 中,设置为"/RiversideInternetForums/avatars/". 应用程序设置"websolutionavatarspath",该应用程序设置为位于位置的光盘。 在提供的示例 Web.config 中,它被设置为" c:riversideinternetforumsavatars"。 最后,应用程序设置"websolutionimagesurl"必须指向找到论坛映像的网站地址。 在示例代码中,这被设置为"/RiversideInternetForums/images/".

论坛的外观。用户管理和其他控件由样式表 websolution.css 决定。 可以定制这里文件以更改各种控件的外观。

论坛概述

在示例 上面 中,只需要一个页面来显示论坛- 即 default.aspx。 自定义控件 RiversideInternet.WebSolution.Forum detemines通过查看查询字符串来呈现什么 HTML。 查询字符串变量 threadid 用于标识要查看的线程。 查询字符串变量 postid 也可以用于指定线程内的帖子。 如果没有指定 postid 或者 threadid,论坛代码就会知道它应该显示论坛线程的分页 List。

每页显示25个线程,如线程标题。线程起始符。回复数。视图数和最后一张报告 NAME。 一个超过 30个帖子的帖子由火灾中的文件夹图像指示。 线程按最后一个帖子的时间降序排列。 因这里,如果有人回复某个线程的List,它将被升高到列表的顶部。

在查询字符串中指定 threadid 或者 postid 时,论坛代码会知道应该显示特定的线程。 不呈现论坛线程的分页 List,而是显示单个线程。 可以在平面视图模式或者树视图模式下显示线程。 在平面视图模式下,线程的顺序是按顺序显示的,每个文章的主体都可以见。 在树视图模式中,线程显示为帖子的层次结构,并类似于CodeProject论坛上的线程。 在这两种模式下,每页显示 30个帖子。 cookie用于存储用户是否处于树视图模式或者平面视图模式,这里设置将影响所有论坛。

在启动新线程。编辑帖子。回复帖子。引用帖子或者执行搜索时,将使用查询字符串变量 forumaction。 除了搜索之外,每个操作都需要用户登录。 如果没有用户登录,网络浏览器将被重定向到登录页面。 成功登录后,浏览器将自动重定向到上一页。 当 forumaction 有"新建"值( 并且没有指定 postid ) 时,论坛控件知道它应该呈现一个表单来启动新线程。 当 forumaction 具有值"答复"( 并且指定了 postid ) 时,论坛控件会呈现一个表单以发送回复。 "报价单"操作类似于"答复"操作,除了被 [QUOTE] 标记包含的邮件外,还包括一些附加文本。 当论坛处于扁平模式时,这是最有用的,因为有时很难识别用户回复的帖子。 当用户编辑帖子时使用操作"编辑"。 用户只能编辑他们编写的文章。

forumaction 等于"搜索"时,论坛代码知道执行搜索。 这种情况下,使用了一个名为 searchterms的附加查询字符串变量,它包含用于搜索论坛的术语。 MATCH 搜索critieria显示在分页 List 中的文章,ORDER BY 发布日期降低。 为了通过搜索标识一个邮件,每个搜索项必须在文章的主体中找到。

用户管理概述

在示例 上面 中,显示用户管理信息只需要一个页面- 即 usermanagement.aspx。 自定义控件 RiversideInternet.WebSolution.UserManagement 确定应该通过查看查询字符串来呈现什么 HTML。 执行的操作取决于查询字符串变量 useraction,它可以采用以下四种可能值之一: "登录","注销","连接"还有"设置"。

useraction 具有"登录"值时,用户管理控件将呈现一个登录窗体,提示用户输入 E-mail 地址和密码。 记住for复选框会将持久的cookie ( 在浏览器会话中保存的) 写入客户端,这将会将用户自动记录到后续浏览器。 如果 useraction 具有"注销"值,用户管理代码将呈现一个包含注销按钮的简单HTML页面。 按下这里按钮后,将注销当前登录的用户。

用户定义的useraction 值"加入"和"设置"用于为用户签名或者修改用户的登录设置。 在每个案例中,用户管理控件呈现一个显示别名。E-mail。密码。确认密码和化身文本框的表单。 用户的别名是在论坛上他或者她所知道的NAME。 用户地址的E-mail 与密码一起使用,以便登录。 当用户提交了"按 E-mail 通知"选项后,它也可能被使用。 当回复这里邮件时,通知 E-mail 被发送到该帖子的作者。 最后,化身文本框被用来将图像上传到web服务器上。 头像是显示在用户信息下方的图片,指向每个帖子的左边。 如果用户未上传头像,则不会在该用户旁边显示任何图像。 头像不得大于 150像素,必须小于,必须以 GIF。JPEG或者PNG格式格式。 论坛的屏幕截图,显示 上面,显示了尼克的母语,Pud和,。 他们的头像,一只狗戴眼镜,一个成功的云云 sprint 和一个猴子都是可以见的。

基于表单身份验证的基于角色的安全性

正如已经说过的,论坛使用"窗体"身份验证来确定用户是否登录或者关闭。 因此,在 Web.config 中找到的身份验证模式应该设置为"窗体"。 论坛使用基于角色的身份验证来确定用户可以执行哪些操作。 用户可以执行的角色存储在数据库字段 WS_Users.Roles 中的逗号分隔的List 中。 当前,必须使用原始SQL或者企业管理器管理 WS_Users.Roles。 具有"forumadmin"角色的用户,可以编辑其他用户的帖子,也可以输入粘性( 固定) 线程。 用户拥有"forumadmin"角色后,可以看到额外的下拉 List,允许管理员用户指定线程是否粘起,以及它应该坚持使用的持续时间。

基于Heath编写的代码实现了基于角色的安全性。 感谢 Heath 有关基于角色安全的更多信息,请阅读Stewart的文章。

由查询字符串控制的功能

为了了解查询字符串控件的功能,需要了解 System.Web.UI.Control的三种常用方法。 即 CreateChildControlsOnPreRenderRender。 为了创建子控件以准备 postback 或者呈现,CreateChildControls 函数通常在复合控件( 如上面描述的论坛和用户管理控件) 中重写。 在呈现之前调用 OnPreRender 来实现控件所需的任何工作,例如从数据库中获取数据。 最后,使用 Render 方法将标记文本( HTML ) 写入输出流。

所有 RiversideInternet.WebSolution 控件( 如论坛和用户管理控件) 都从 WebSolutionControl 派生。 WebSolutionControl 反过来派生自 System.Web.UI.WebControls.WebControlSystem.Web.UI.Control 派生的重要内容重要的是,在 WebSolutionControl 中,有三个函数被重写: CreateChildControlsOnPreRenderRender

publicclass WebSolutionControl : WebControl, INamingContainer
{
. . .
 private WebSolutionObject _webSolutionObject;
 protectedvirtualvoid CreateObject()
 {
 }
 protectedoverridevoid CreateChildControls()
 {
 CreateObject();
 if (_webSolutionObject!= null)
 _webSolutionObject.CreateChildControls();
 }
 protectedoverridevoid OnPreRender(System.EventArgs e)
 {
 if (_webSolutionObject!= null)
 _webSolutionObject.OnPreRender();
 }
 protectedoverridevoid Render(System.Web.UI.HtmlTextWriter writer)
 {
 if (_webSolutionObject!= null)
 _webSolutionObject.Render(writer);
 }
. . .
}

OnPreRenderRender 之前调用的CreateChildControls 调用虚函数 CreateObjectCreateObject的任务是创建一个 WebSolutionObject 并在成员变量 _webSolutionObject 中存储它的引用。 WebSolutionObject 类包含一些常用的函数和三个 public 虚拟函数 CreateChildControlsOnPreRenderRender。 在调用 CreateObject 之后,函数 _webSolutionObject.CreateChildControls 调用。CreateChildControls 是对 OnPreRenderRender的调用,这些函数只是通过调用 _webSolutionObject.OnPreRender_webSolutionObject.Render. 来委派工作。

Forum 控件重写 CreateObject,以创建 ForumThreadsForumThreadForumForm 或者 ForumSearch 对象,具体取决于查询字符串。 由于这些对象派生自 WebSolutionObject,它们可以实现。OnPreRenderRender 函数。 这四个类负责实现上述论坛概述部分中描述的四个功能领域。

类似地,UserManagement 控件重写 CreateObject,以根据查询字符串创建 UserLoginUserLogoff 或者 UserSettings 对象。 这三个类是 reponsible,用于实现上述用户管理概述部分中描述的三个功能。

还应该注意的是 WebSolutionControl 实现了 INamingContainerINamingContainer 是不具有任何方法但导致页面在每个 WebSolutionControl 下创建新命名范围的marker 接口。 实现这里接口时,包含的任何子控件都保证具有在页上真正唯一的标识符( 由 UniqueID 属性表示)。

数据库访问层

实现Riverside网络WebSolution中的所有控件都使用中间层组件提供WebSolution控件与 SQL Server 数据库之间的通信。 中间层组件由 ForumDBUserDB 组成。 只有这些类使用 System.DataSystem.Data.SqlClient,信息通过简单的helper 类传递回WebSolution控件。

例如 UserDB 有一个 static 函数 GetUser,它接受用户标识符( 整数) 作为输入参数,并返回关于指定用户的信息。 返回与 WS_Users 表中找到的每个字段对应的属性 AliasAvatarEmailPasswordPostCountUseAvatarUserIDWebID的信息。

用于在中间层数据库访问层和服务器控件之间进行通信的其他类包括: ForumThreadInfoForumSearchInfoForumPost。 查看论坛线程的分页 List 时,在 List 中呈现每一行所需的信息都是从 ForumThreadInfo 对象获取的。 实际上,函数 ForumDB.GetThreads 返回一个 ForumThreadInfoCollection,它是 ForumThreadInfo的一个 tmodel,这个集合用于呈现论坛线程的分页 List。 论坛搜索结果以相同的方式进行编码。 但是,在这种情况下 ForumDB.GetForumSearchResults 返回 ForumSearchInfoCollection

ForumDB.GetThreads 调用存储过程 WS_GetThreads,它接受三个输入参数: 论坛标识符( @ForumID int ),页面大小( @PageSize int ) 和页面索引( @PageIndex int )。 查询字符串变量 threadspage ( 页面索引) 用于确定用户查看哪个线程页。 在页面大小 25和 threadspage 等于 1的情况下,第一个 25线程可见。 当 threadspage 等于 2时,线程 26 -50可见等。 值得注意的是 WS_GetThreads 并没有将所有的论坛线程返回到web服务器。 相反,它会根据 @PageSize@PageIndex 返回一个线程页。 通过这种方式,网络流量减少,数据库服务器上的硬件工作通常能够获得最佳性能。 此外,分页结果以这种方式大大简化了 C# 代码。

通过创建临时表 #PageIndex ( 在 WS_GetThreads 中创建一个包含一个标识字段 IndexID。和一个 threadid 字段,其中所有属于特定论坛的线程标识符都被插入了。 存储过程 WS_GetThreads 然后选择并只返回 #PageIndex 中存储的线程子集,具体取决于 @PageSize@PageIndex

CREATEPROCEDURE WS_GetThreads
(
 @ForumID int,
 @PageSize int,
 @PageIndexint)ASDECLARE@PageLowerBoundintDECLARE@PageUpperBoundintSET@PageLowerBound = @PageSize * @PageIndexSET@PageUpperBound = @PageLowerBound + @PageSize + 1CREATETABLE #PageIndex 
(
 IndexID intIDENTITY (1, 1) NOTNULL,
 ThreadID int)INSERTINTO #PageIndex (ThreadID)SELECT 
 ThreadIDFROM 
 WS_ThreadsWHERE 
 ForumID = @ForumIDORDERBY 
 PinnedDate DESCSELECT. . .FROM WS_Threads,.. ., #PageIndex PageIndexWHERE WS_Threads.ThreadID = PageIndex.ThreadID AND PageIndex.IndexID> @PageLowerBound AND PageIndex.IndexID <@PageUpperBound AND. . .ORDERBY PageIndex.IndexIDGO

在paging中描述的分页技术最初的思想是在存储过程 WS_GetThreadsWS_GetForumSearchResults 中找到的,来自 http://www.asp.net/插件论坛。

最后,有几个关于 WS_ThreadsWS_Posts 表的说明,它在论坛控件的核心。 当新线程启动时,会在 WS_PostsWS_Threads 表中插入一行。 WS_Posts.PostID 是一个标识字段,因此在将一行插入到 WS_Posts 时自动分配一个惟一值。 插入到 WS_Threads 中的行将 threadid 设置为自动生成的值( WS_Posts.PostID )。 当对一个线程进行回复时,行被插入到 WS_Posts 中。 ParentPostID 字段被设置为回复的邮件的标识符。 当新线程启动时,插入到 WS_Posts的行的ParentPostID 等于 0 - 即它没有父节点。 对于插入到WS_Posts中的每个回复,WS_Threads.Replies 增加 1,WS_Threads.LastPostedPostID 被更新为反映特定线程的文章。

table WS_Posts 具有字段 PostLevelTreeSortOrderFlatSortOrder,以便存储过程 WS_GetThread 能够快速获得线程帖子的分页 List。 在树视图模式下查看线程时使用 PostLevelTreeSortOrder,而在平面视图模式下查看线程时使用 FlatSortOrder

PostLevel 字段指示树视图hiearchy中的深度。 启动线程时,会使用 PostLevel 0将一行插入到 WS_Posts 中。 对这里帖子的回复将有 PostLevel 1. 对这些帖子的回复将有 PostLevel 2. 在屏幕上,PostLevel 指示在呈现后从左边边缘的水平标识的大小。 TreeSortOrder 字段维护在树视图模式中显示日志的顺序。 启动新线程时,将在 WS_Posts 中插入一行,TreeSortOrder 等于 0 ( 呼叫这里日志 1 )。 对这个帖子的第一个回复将有 TreeSortOrder 1 ( 发布 2 )。 再次回复 1将导致另一行插入到 WS_Posts 中,使用 TreeSortOrder 2 ( 发布 3 )。 然而,如果回复发送到 2 ( 呼叫这里日志 4 ),这里邮件将假定 TreeSortOrder 2与第 3个后沿 TreeSortOrder 3转移。

描述PostLevel和TreeSortOrder的图像

描述PostLevel和TreeSortOrder的图像

FlatSortOrder 字段维护在平面视图模式中显示帖子的顺序。 在平面视图模式下,帖子的显示顺序为最早到最新。 因此,当一个新线程启动时,第一个帖子有 FlatSortOrder 0. 后续答复的FlatSortOrder 等于 1,2,3等。

图像说明 FlatSortOrder

在存储过程 WS_AddPost 中,PostLevelTreeSortOrderFlatSortOrder 会自动更新,这是基于 http://www.asp.net/ 论坛中的一个类似存储过程。

有趣的Fragment

下面是一些值得讨论的有趣的Fragment和 Fragment。

上传和验证头像

当"加入"或者"设置"模式下,UserManagement 控件可以方便地从客户端机器到web服务器上的化身上传。 头像不得大于 150像素,小于或者等于 150,大小为 GIF。JPEG或者 PNG。 在 ASP.NET 中,很容易将文件上传到web服务器,使用 System.Web.UI.HtmlControls.HtmlInputFile 控件。但是,为了使它的工作,Web窗体( 在提供的示例代码中,usermanagement.aspx ) 必须具有设置为"多部分/表单数据"的属性值。 可以在 UserSettings 类中找到上传的代码,而验证上传的文件( 尺寸,尺寸,类型)的代码可以在 ValidAvatar 类中找到。 System.Web.UI.WebControls.BaseValidatorHtmlInputFile 控件在 ValidAvatar 中用于验证大小和类型,而 System.Drawing.Image 类用于验证图像维度。

从 ASP.NET 应用程序发送 E-mail

ForumForm 类中的函数 EmailReplyNotification 演示如何使用 System.Web.Mail.MailMessageSystem.Web.Mail.SmtpMail 类发送 E-mail。

大小写不敏感字符串替换

ForumText 类用于执行论坛字符串操作,例如替换文本类似:),;): ( 含有适当的符号。 特别有趣的是 FormatDisableHtml 函数,它将潜在恶意 HTML ( 如 <脚本) 替换为 & lt ;脚本。 由于HTML不区分大小写,所以 <脚本的所有大写和小写组合( 例如: <脚本,<脚本和 <脚本必须由 & lt替换;脚本。 为这里,需要一个不区分大小写的字符串替换,不幸的是 System.String 类的替换方法是区分大小写。 Google的快速搜索揭示了的这篇文章,其中的代码WebSolutionUtils.ReplaceCaseInsensitive 基于。

仍然要做的事情

Riverside互联网WebSolution进行中,仍然有许多事情需要代码和改进。 论坛仍然要做的事情包括:

  • 删除没有 Having的日志以使用原始SQL语句的管理员权限 !
  • 时区管理。
  • 改善用户管理控制。
  • 利用利用来改进外观和感觉的方式 System.Web.UI.WebControls.WebControl 属性.
  • 改进 Visual Studio. NET. 中的设计时间支持
  • 改进错误处理。
  • 实现无法答复的帖子。
  • 改进搜索。
  • 等等。

历史记录

版本 1 - 9th 2003年06月

  • 这是上传到CodeProject的第一个版本。

版本 2 - 13th 2003年08月

  • 线程 List 中的最后一栏现在显示最后一篇文章的日期和时间,并提供一个链接以直接。
  • 基于角色的表单认证。 具有"forumadmin"角色的用户可以修改其他用户的帖子,并张贴固定的( 置顶) 线程。
  • 添加了动态树视图模式。
  • 通过删除threadpage和threadid参数简化了 QueryString。 而是使用单个postid参数。
  • WS_Users.UseAvatar 字段已经过时,因此已经删除。
  • WS_Threads.IsPinned 字段已经过时,因此已经删除。
  • 为基于角色的身份验证添加的WS_Users.Roles 字段。
  • 修正回复通知 Bug的邮件。
  • 固定 Bug,在搜索列表中显示别名和发布主题时可以执行恶意 HTML。
  • 固定 Bug,用"& lt ;选择"替换单词"选择"。
  • 固定 Bug,意味着在用户设置和 Join 页面上不总是需要确认密码。
  • 以前,更新用户的设置可能会导致用户的头像被删除。 这里 Bug 已经被修复。
  • 使用 WebSolution.zip ( 上下载) 中的文件 update1to2.sql 将数据库从版本 1更新到版本 2.

INT  for  Intern  Forum  Forums  
相关文章