65.9K
CodeProject 正在变化。 阅读更多。
Home

将 Telerik RadControls 与 DotNetNuke 结合使用。完整的评分和评论解决方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (8投票s)

2010年6月14日

CPOL

8分钟阅读

viewsIcon

49616

downloadIcon

597

本教程展示了在 DotNetNuke 中使用 Telerik 控件。它将引导您完成为整个 DotNetNuke 页面或任何其他由 URL 标识的内容创建评分/评论解决方案的过程。

下载文章的完整源代码 - 3.8 KB

DotNetNuke Telerik Tutorial: RadRating and RadChart usage

教程的实时演示

引言

DotNetNuke 5.2+ 附带功能强大的 Telerik 控件库。鉴于 Telerik 控件是典型的 ASP.NET 库,您可能会认为需要 Visual Studio 来创建使用出色的 Telerik 控件和功能的模块。在这里,我将向您展示如何在不开发和部署任何模块的情况下将 Telerik 控件添加到您的 DotNetNuke 网站页面。您需要的所有工具都是免费且开源的。您需要 DotNetNuke 社区版 5.2 或更高版本以及 XsltDb 01.01.24 或更高版本。

对于这个 Telerik-DotNetNuke 教程,一个非常好的任务是创建一个页面评分/评论系统。对于评分,我使用了两个 Telerik 控件:RadRating 和 RadChart,并实现了一个类似于 codeproject 文章评分的评分系统。评分子系统必须支持以下功能:

  • 显示当前页面评分,
  • 显示投票柱状图:投票如何按值分布,
  • 允许访问者投票,
  • 使用 cookie 控制访问者投票,如果访问者已经投票,系统将删除之前的投票。这允许访问者更正/更改他们的投票,但可以防止投票重复。

对于评论,我使用 RadEditor 来输入评论文本,并使用 RadComboBox 来输入姓名/电子邮件/网站。为什么选择 Combo?RadTextBox 不支持圆角。但是,可以设置一个组合框来输入文本而不使用下拉功能。我相信 Telerik 在未来的版本中将支持 RadTextBox 和 RadEditor 的圆角。评论子系统必须支持以下功能:

  • 按时间顺序排列的评论列表,
  • 评论提交表单,
  • 评论者头像,
  • 网站管理员删除评论,
  • 新评论电子邮件通知。

还有一件事需要定义。评分/评论的对象是什么?实际上,我们不需要知道对象是什么,只需要它的 ID。在 Web 中,我们可以可靠地使用 URL 作为内容 ID。实际 URL 可能包含其他不标识内容的参数,因此在构建要评分/评论的内容 ID 时必须将其过滤掉。

您可以在阅读之前在线查看

内容识别

有两种方法可以获取当前 URL

  • URL 重写后:mdo:aspnet('Request.Url.PathAndQuery')
  • URL 重写前:mdo:aspnet('Request.RawUrl')

您必须决定哪种方法适合您。我在这里使用原始客户端 URL。因此,PageID 的构建如下:

<xsl:variable name="page-id" select="mdo:aspnet('Request.RawUrl')" />

为了提供可靠的门户识别,我们使用相对 URL 和 XsltDb 的数据隔离功能。因此,用于已识别内容的数据库表将如下所示:

create table {databaseOwner}MDO_PageRating
(
  PageID int identity primary key,
  PortalID int,
  PageGuid nvarchar(256)
)

为了简化内容识别,我们使用以下组合存储过程,该过程检查页面是否已识别,如果未识别,则插入新记录并返回其 ID:

create procedure {databaseOwner}MDO_PageRating_EnsurePage
    @PortalID int,
    @PageGuid nvarchar(max),
    @PageID int out
as
begin
    select @PageID = PageID from MDO_PageRating
    where PageGuid = @PageGuid and PortalID = @PortalID
    
    if @PageID is null begin
        insert {databaseOwner}MDO_PageRating(PortalID, PageGuid)
        values(@PortalID, @PageGuid);
    
        set @PageID = SCOPE_IDENTITY();
    end;
end;
)

现在我们可以开始评分了。

评分子系统

数据库对象

首先,我们必须创建一个存储每次投票的表。

create table {databaseOwner}MDO_PageRating_Rate
(
    RateID int identity primary key,
    PageID int constraint MDO_PageOfRating foreign key references MDO_PageRating(PageID)
        on delete cascade on update cascade,
    Value float,
    Cookie uniqueidentifier
)
    

我们需要 2 个存储过程:用于注册新投票和检索有关投票的信息。新投票注册

create procedure {databaseOwner}[{objectQualifier}mdo_xslt_rate_page]
    @PortalID int,
    @PageGuid nvarchar(max),
    @Value float,
    @Cookie nvarchar(max)
as
begin
    declare @PageID int;
    exec {databaseOwner}MDO_PageRating_EnsurePage @PortalID, @PageGuid, @PageID out;

    delete MDO_PageRating_Rate
    where PageID = @PageID
    and Cookie = @Cookie;
    
    insert {databaseOwner}MDO_PageRating_Rate(PageID, Value, Cookie)
    values(@PageID, @Value, @Cookie);
end;
    

投票和评分查询

create procedure {databaseOwner}[{objectQualifier}mdo_xslt_page_rating]
    @PortalID int,
    @PageGuid nvarchar(max)
as
begin
    select pr.* from {databaseOwner}MDO_PageRating_Rate pr
    join {databaseOwner}MDO_PageRating p on p.PageID = pr.PageID
    where p.PageGuid = @PageGuid
    and p.PortalID = @PortalID;
    
    select
        SUM(StatCount) TotalVotes,
        MAX(StatCount) Height,
        SUM(StatValue * StatCount) / SUM(StatCount) Average
    from (
        select pr.Value StatValue, COUNT(*) StatCount
        from {databaseOwner}MDO_PageRating_Rate pr
        join {databaseOwner}MDO_PageRating p on p.PageID = pr.PageID
        where p.PageGuid = @PageGuid
        and p.PortalID = @PortalID
        group by pr.Value) t;
end;
    

此存储过程返回 2 个结果集:投票列表和柱状图的评分摘要。在评分摘要中,我们有投票总数、最大柱状图高度和当前平均评分。

显示当前评分

为了显示当前内容的评分,我们创建了 2 个对象 RadRating – 显示页面的平均评分,以及 RadChart – 显示投票分布。所以我们进行 3 个步骤:

1. 从数据库读取当前页面评分信息

<xsl:variable name="rating" select="mdo:xml('page-rating', 'rating, total', $page-id)" />

2. 创建一个 RadRating 控件来显示当前评分

<telerik:RadRating ID="PageRating" runat="server" Value="{mdo:coalesce($rating//Average, 0)}" ReadOnly="True" Skin="Office2007" />

3. 创建 RadChart 控件来显示投票分布

<telerik:RadChart runat="server" ID="RadChart2" ChartTitle-Visible="false" Width="100" Height="50" Skin="Office2007" >
  <Series>
    <telerik:ChartSeries Type="Bar">
      <Items>
        <xsl:for-each select="mdo:sequence(1,5,1)">
          <telerik:ChartSeriesItem XValue="{current()}"
                                 YValue="{count($rating//rating[Value=current()])+0.3}"
                                 Label-TextBlock-Text="{count($rating//rating[Value=current()])}"/>
        </xsl:for-each>
      </Items>
    </telerik:ChartSeries>
  </Series>
  <PlotArea Appearance-Dimensions-Margins="0,0,0,0">
    <XAxis AutoScale="False" MinValue="0.5" MaxValue="5.5" Step="1" />
    <YAxis AutoScale="False" MinValue="0"
          MaxValue="{mdo:coalesce($rating//Height,0) + 1}"
          Visible="False" />
  </PlotArea>
  <Legend Visible="false"/>
</telerik:RadChart>
    

上面的一些列表片段需要澄清。

  • <xsl:for-each select="mdo:sequence(1,5,1)"> 执行从 1 到 5 的循环。XSL 不支持循环变量,因此 XsltDb 提供了一个 mdo:sequence 函数,它返回 XML 节点,这些节点实际上是循环变量的值列表。当前值可以使用标准 xsl 函数 current() 捕获。
  • YValue="{count($rating//rating[Value=current()])+0.3}" 允许我们在没有此类投票的情况下创建高度为 0.3 的条形。
  • MaxValue="{mdo:coalesce($rating//Height,0) + 1}" 分配一个垂直刻度以在条形上方留出数字空间。

评分输入控件

为了让访问者投票,我们创建了另一个 RadRating 控件,如下所示:

<telerik:RadRating ID="PageRating2" runat="server" Value="{mdo:coalesce($rating//Average, 0)}" OnClientRated="onClientRated" Skin="Office2007"
  >
  <Items>
    <telerik:RadRatingItem Value="1" ToolTip="Poor" />
    <telerik:RadRatingItem Value="2" ToolTip="Fair" />
    <telerik:RadRatingItem Value="3" ToolTip="Good" />
    <telerik:RadRatingItem Value="4" ToolTip="Excellent" />
    <telerik:RadRatingItem Value="5" ToolTip="Awesome" />
  </Items>
</telerik:RadRating>

为了更好地理解星级的含义,我为 RadRating 控件中的每个星级分配了一个有意义的标签。最初,它显示了页面的当前评分 (Value="{mdo:coalesce($rating//Average, 0)}") 并订阅了一个评分事件 (OnClientRated="onClientRated")。JavaScript 函数 onClientRated 非常简单:

function onClientRated(sender, args)
{
  {{mdo:submit('@rate', '@sender.get_value()')}}
}
    

它只是获取访问者提供的评分值并将其提交到服务器。请注意,@rate 中的 @ 符号表示 XsltDb 只保留 @rate 的值一个请求(类似命令的行为)提交值中的 @ 符号表示这是 javascript 代码,必须在提交之前对其进行评估。

在评分提交到服务器后,我们必须将其保存到数据库。代码很简单:

<xsl:if test="mdo:param('@rate')">
  <xsl:if test="not(mdo:cookie('rater'))">
    <xsl:if test="mdo:set-cookie('rater', mdo:newid(), '2020-01-01')" />
  </xsl:if>

  <xsl:if test="mdo:xml('rate-page', '$script', $page-id, mdo:param('@rate'), mdo:cookie('rater'))" />

  {{mdo:redirect(mdo:aspnet('Request.RawUrl'))}}

</xsl:if>

您可以看到,只需要 3 个步骤即可将评分值发送到数据库。

首先,检查访问者是否已识别。如果没有,则创建一个 cookie。我使用 mdo:newid() 作为 cookie 值。mdo:newid() 生成一个 guid,因此访问者是唯一标识的。

其次,将新的评分值发送到数据库。DB 将检查访问者是否是新访客并插入新的评分,或者访问者是否已对该内容评分,DB 将替换之前的投票。

第三,我们重定向到当前页面。这并非必需,但我建议进行此重定向,因为:

  • 您结束了页面生命周期并开始了新的页面生命周期,因此您的标准 ASP.NET 控件和 Telerik 控件将恢复到初始状态。这使我们无需编写清理代码即可将控件值重置为初始状态,而不会破坏 ASP.NET 页面生命周期。
  • 当访问者按 F5 时,他不会看到是否要重新发送数据到服务器的难看的消息框。它还防止数据向服务器重复提交。

评分子系统已基本完成,切换到评论子系统

评论子系统

数据库对象

与评分一样,这里我们需要一个表来存储评论,以及 3 个存储过程来检索评论列表、将新评论保存到数据库以及按管理员删除评论。

create table {databaseOwner}MDO_PageRating_Comment
(
    CommentID int identity primary key,
    ParentID int,
    PageID int constraint MDO_PageOfComment foreign key references MDO_PageRating(PageID)
        on delete cascade on update cascade,
    Comment nvarchar(max),
    EMail nvarchar(128),
    URL nvarchar(128),
    Name nvarchar(128),
    DTCreated datetime default getdate()
)
create procedure {databaseOwner}[{objectQualifier}mdo_xslt_comment_page]
    @PortalID int,
    @PageGuid nvarchar(max),
    @ParentID int,
    @Comment nvarchar(max),
    @Name nvarchar(max),
    @EMail nvarchar(max),
    @URL nvarchar(max)
as
begin
    declare @PageID int;
    exec {databaseOwner}MDO_PageRating_EnsurePage @PortalID, @PageGuid, @PageID out;
    
    if @ParentID < 1 set @ParentID = null;

    insert {databaseOwner}MDO_PageRating_Comment(ParentID,PageID,Comment,EMail,URL,Name)
    values(@ParentID,@PageID,@Comment,@EMail,@URL,@Name);
end;
create procedure {databaseOwner}[{objectQualifier}mdo_xslt_page_comments]
    @PortalID int,
    @PageGuid nvarchar(max)
as
begin
    select c.* from {databaseOwner}MDO_PageRating_Comment c
    join {databaseOwner}MDO_PageRating p on p.PageID = c.PageID
    where p.PageGuid = @PageGuid
    and p.PortalID = @PortalID;
end;

create procedure {databaseOwner}[{objectQualifier}mdo_xslt_delete_page_comment]
    @PortalID int,
    @CommentID int
as
begin
    delete {databaseOwner}MDO_PageRating_Comment
    where CommentID = @CommentID
    and PageID in (select PageID from {databaseOwner} MDO_PageRating where PortalID = @PortalID);
end;

评论输入表单

我喜欢圆角,所以我想使用 Telerik 控件来创建圆角输入框。问题是 RadTextBox 不提供圆角选项。因此,我改用 RadComboBox。以下代码使用 RadComboBox 创建了一个具有圆角的输入框:

<telerik:RadComboBox runat="server" ShowToggleImage="False" ShowDropDownOnTextboxClick="False" AllowCustomText="True"/>

这种方法适用于评论者的姓名、电子邮件和网站字段。我还希望我的评论易于阅读,所以我为评论本身使用了 RadEditor。我只允许评论者使用基本格式,因此我必须列出评论窗口中允许的工具:

<telerik:RadEditor runat="server" ID="Message" EditModes="Design" Width="491px" Height="200px">
      <Tools>
            <telerik:EditorToolGroup >
                <telerik:EditorTool Name="Bold" />
                <telerik:EditorTool Name="Italic" />
                <telerik:EditorTool Name="Underline" />
            </telerik:EditorToolGroup>
            <telerik:EditorToolGroup >
                <telerik:EditorTool Name="InsertUnorderedList" />
                <telerik:EditorTool Name="InsertOrderedList" />
            </telerik:EditorToolGroup>
            <telerik:EditorToolGroup >
                <telerik:EditorTool Name="JustifyLeft" />
                <telerik:EditorTool Name="JustifyCenter" />
                <telerik:EditorTool Name="JustifyRight" />
                <telerik:EditorTool Name="JustifyFull" />
            </telerik:EditorToolGroup>
            <telerik:EditorToolGroup >
                <telerik:EditorTool Name="Cut" />
                <telerik:EditorTool Name="Copy" />
                <telerik:EditorTool Name="Paste" />
            </telerik:EditorToolGroup>
           </Tools>     
</telerik:RadEditor>

在 RadEditor 下面,我放了一个提交评论表单的按钮:

<input type="button" onclick="{mdo:jsubmit('@comment', 'yes')}" value="Save Comment" />

我想让我的“发送评论”按钮像其他控件一样使用 Office2007 皮肤进行样式设置。为此,我使用 RadFormDecorator,它允许我将皮肤应用于页面的特定区域。

<telerik:RadFormDecorator runat="server" DecorationZoneID="rating-and-comments" Skin="Office2007"/>
<!-- All controls go here -->
<div id="rating-and-comments">
</div>

服务器端评论处理

评论提交后,我们必须将其存入数据库,并通知网站/页面所有者内容已被评论。代码如下:

<xsl:if test="mdo:param('@comment')">
    <xsl:if test="mdo:xml('comment-page', '$script', $page-id, -1,
        mdo:url-decode(mdo:request(mdo:client-name('Message'))),
        mdo:request(mdo:client-name('Name')),
        mdo:request(mdo:client-name('EMail')),
        mdo:request(mdo:client-name('Url'))
    )" />

  <xsl:variable name="mail">
    <p>
      New comment added to the site http://xsltdb.com.
      <a href="http://xsltdb.com{mdo:aspnet('Request.RawUrl')}">Click here to read comments.</a>
    </p>
  </xsl:variable>
  <xsl:if test="mdo:mail('admin@xsltdb.com', 'admin@xsltdb.com', 'New comments added', mdo:text($mail))" />

  {{mdo:redirect(mdo:aspnet('Request.RawUrl'))}}
</xsl:if>

在这里,我们进行 3 个步骤:

1. mdo:xml('comment-page', '$script'…) 将新评论保存到数据库。这里我想澄清如何检索 ASP.NET 控件的值。通常,ASP.NET 控件有一个相关的隐藏输入来存储值。您可以使用 mdo:client-name() 函数获取控件的名称。此函数获取 ASP.NET 控件的本地 ID 并返回控件隐藏输入的全局客户端名称。之后,您可以使用 mdo:request() 函数获取值。RadEditor 在此输入中存储 URL 编码的文本,因此在将其发送到数据库之前,我们必须使用 mdo:url-decode() 函数对其进行解码。

2. 评论保存到数据库后,我们使用 mdo:mail() 函数创建并发送一封电子邮件给网站管理员。此函数发送我们构建为 XSL 变量并使用 mdo:text() 函数转换为字符串的 HTML 消息。

3. 处理完成后,我们使用 mdo:redirect() 重新启动 ASP.NET 页面生命周期,正如我们对评分所做的那样。

显示评论

为了显示页面的评论列表,我们首先从数据库读取评论列表:

<xsl:variable name="comments" select="mdo:xml('page-comments', 'comment', $page-id)" />

以下代码显示评论列表:

<xsl:for-each select="$comments//comment">
  <div style="width:100px;float:left;">
    <img src="http://www.gravatar.com/avatar/{mdo:md5(EMail)}" />
    <div style="color:grey">
      <a rel="external nofollow" style="font-size:smaller" href="{URL}">{{Name}}</a>,
      {{mdo:fmt-date(DTCreated, 'd')}}
    </div>
  </div>
  <div style="float:left;background-color:white;width:375px;padding:10px;border:1px solid silver;">
    {h{Comment}}
    <div style="padding-top:45px;">
      <xsl:if test="mdo:isinrole('Administrators')">
        <a href="{mdo:jsubmit('@delete-comment', CommentID)}" class="CommandButton">Delete</a>
      </xsl:if>
    </div>
  </div>
  <div style="clear:both"/>
</xsl:for-each>

此代码为每条评论显示以下内容:

  • 评论者图片。这非常简单,因为我们有 gravatar 服务。只需获取电子邮件并创建一个评论者图片 URL:src="http://www.gravatar.com/avatar/{mdo:md5(EMail)}"
  • 评论文本以 HTML 显示。{h{Comment}} 由于我们使用 RadEditor,我们可以确保 HTML 不包含脚本部分。
  • 如果当前用户是门户管理员,他必须能够删除评论。因此,我们在 <xsl:if test="mdo:isinrole('Administrators')"> 之后有一个代码块来执行此操作。

结论

本教程演示了如何创建具有平面评论的简单评分/评论系统。在 实时演示 中,我们可以看到稍微复杂一些的带回复的评论。这不包含在文章文本中,但文章附件包含来自 xsltdb.com 网站的真实代码,该代码支持评论回复。我将此功能排除在文章之外是为了减小文章的篇幅,因为它没有展示 Telerik Controls 或 XsltDb Module 的独特功能。

使用文章附带的代码

要使用此代码,您需要 DotNetBuke 5.2 或更高版本,推荐版本为 5.4.2。部署非常简单:

  • 以超级用户身份登录您的 DotNetNuke 网站。
  • 安装 XsltDb 模块,在此处下载
  • 创建数据库对象。转到 Host/SQL 选项卡,将 DatabaseObject.sql 粘贴到文本框中,选择 RunAsScript,然后单击 Execute。
  • 导航到您想要评分/评论的页面。将新的 XsltDb 模块添加到页面。点击 EditXSLT 链接。将 ModuleCode.xslt 粘贴到文本区域。查看代码并更改您的电子邮件和 URL。点击 Update & Publish。
  • 享受评分/评论。

用于创建评论/评分模块的工具

  • Windows Server 2008 / IIS 7.5 / .NET 3.5
  • DotNetNuke 5.4.2 社区版,内置 Telerik RadControls
  • XsltDb DotNetNuke 集成模块
© . All rights reserved.