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

ASP.NET MVC 2 投票控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (10投票s)

2011 年 4 月 20 日

CPOL

7分钟阅读

viewsIcon

41309

downloadIcon

2038

简单的投票控件,用于 MVC 项目,使用局部视图

Vote Control

引言

这是一个简单的投票控件,用于 MVC 项目。它实现为一个局部视图,因此可以根据需要包含在任何地方。

主要特点

  • 易于包含在任何视图中
  • 问题、答案和投票存储在 XML 文件中(每个投票控件一个文件)
  • 可配置样式
  • AJAX 调用更新结果
  • 所有投票控件的通用 JavaScript 和样式表

Using the Code

在源代码中,我在默认的 Index.aspx 页面中添加了两个投票控件。这些是通过在视图中使用以下代码包含的:

<%
   VoteDataModel petModel = (VoteDataModel)ViewData[VoteDataModel.GetViewDataName("Pet")];
   petModel.ControlWidth = 200;
   Html.RenderPartial("VoteControl", petModel);
%>

在上面的代码中,我们指定了投票控件的名称 (Pet) 和宽度 (200)。

为了使其正常工作,您需要在视图顶部,紧跟在 page 指令下方添加以下这行:

<%@ Import Namespace="VoteControl.Models"%>

另外,在这种我使用了默认母版页的情况下,您必须在母版页的 head 部分添加样式表和 JavaScript 包含:

<link href="~/Content/VoteControl.css" rel="stylesheet" type="text/css" />
<script src='<%= Url.Content("~/Scripts/VoteControl.js") %>' type="text/javascript">
</script>

我将它们添加在 Site.css 的包含之后。如果我们不使用母版页,这些行将直接包含在页面中。

在控制器中,必须使用以下代码构造模型并将其传递给视图:

VoteDataModel model = new VoteDataModel
			("Pet", Request.PhysicalApplicationPath + "App_Data\\");
model.Open();
ViewData[model.ViewDataName] = model;

整个页面(在对两个投票进行投票后)如下所示:

Vote Control

命名约定

投票控件的名称在 VoteDataModel 构造函数中指定。它必须是唯一的,并以各种方式使用,例如 XML 文件名 - NamePoll.xml(存储在 app_data 目录中)。

实现

代码由以下新文件组成:

  • 模型 - VoteModel.cs
  • 控制器 - VoteController.cs
  • 局部视图 - VoteControl.ascx
  • 脚本 - VoteControl.js
  • 样式表 - VoteControl.css
  • App_Data - 包含投票控件数据的 XML 文件

文件位于解决方案中您期望的位置,如下所示:

Solution Files

此外,我还修改了 Global.asax,以便将路由 ~/DoVote/{name}/{id} 重定向到 VoteController

routes.MapRoute(
    "VoteButton", // Route name
    "DoVote/{uniqueName}/{voteId}", // URL with parameters
    new { controller = "Vote", action = "DoVote" },
    new { voteId = @"\d{1,3}" } // voteId can only be numeric, and less than 1000
);

这在按下投票按钮时用于 AJAX 调用。然后,此调用的结果用于使用新的投票/百分比更新控件。

幕后

大部分代码都在模型中(应该如此)。

VodelDataModel 对象包含一个答案列表 (List<AnswerItem>) 和 IP 地址列表 (List<IpAddressItem>)。每个答案都有一个 AnswerItem,并且为每个唯一的客户端 IP 地址添加一个条目。这就是我们确保用户只投票一次的方式。这并不完美 - 请参阅“兴趣点”部分了解更多详细信息。

模型中提供了以下 public 方法:

static string GetViewDataName(string uniqueName) and string ViewDataName

这会获取一个将用于视图数据的名称。我们在控制器和视图中使用它 - 其中有一个 static 方法用于视图,还有一个实例属性用于控制器。

public VoteDataModel(string name, string path)

对象构造函数。

public bool Open()

构造对象后应始终调用 Open。这会从 XML 文件读取数据。

public bool DoVote(int voteId, string ipAddr)

线程安全 - 请参阅最后一节。

这会更新对象和文件。如果投票被接受,则返回 true;如果找到 IP 地址(即用户已投票),则返回 false

public int GetPercentage(int index)

这用于局部视图显示百分比。

public int GetBarLength(int index, int controlWidth)

这用于局部视图显示百分比条。

局部视图 HTML

控件有三个 div 用于不同的视图:

Vote Control HTML

第一个默认显示。其他两个默认在内联样式中设置为 display:none。根据按下哪个按钮或链接,其中一个被设置为显示,另外两个被设置为 display:none

JavaScript

我决定使用纯 JavaScript 进行 AJAX 调用,但我也可以使用 jquery(或 MicrosoftAjax.js 文件)。我选择此方法是因为我希望在此方面尽可能灵活(和透明)。您可能希望将其更改为使用 jquery - 尤其是在现有页面上已经使用 jquery 的情况下。请注意,我已经删除了未使用的脚本(jquery 和 MicrosoftAjax),因为否则下载量会非常大!

还有另外两个函数 - 这些函数用于显示或隐藏与问题、百分比答案或带投票数的答案相关的控件。

样式表

VoteControl.css 样式表中的大多数元素都有类 - 希望名称相当直观。特别是,您可能希望更改颜色以适应您网站的配色方案 - 为此,请注意正常行和交替行可以(并且在示例中)以不同颜色着色。

关注点

  1. 控件包含在一个 DIV 中,但如果您需要任何特殊格式,最简单的方法可能是将控件包装在另一个 DIV 中(在包含局部视图的视图中),并为其应用其他 style 属性。示例代码显示了如何浮动“pet”控件,使其可以嵌入文本部分。
  2. 在控制器中,我构造模型并将其在 ViewData 中传递给视图。这可以通过许多其他方式实现 - 我这样做的方式不一定是最好的方法。您可能希望以适合您特定项目的方式进行。
  3. 在包含 cssjavascript 文件的地方,我使用了 ~/...Url.Content("~/...")。这些不同的原因是 CSS 包含是服务器端包含,而 JavaScript 包含是客户端包含。但重要的是,通过使用“~”,文件路径将始终正确,无论我们在哪里包含此代码,它都会添加虚拟目录(如果需要)。虚拟目录在本地与托管版本不同是很常见的 - 但这两种情况都适用。
  4. 需要两种类型的线程安全。我们需要确保文件不会同时被两个线程写入,或者在写入时被读取。这是通过对 static 对象进行锁定来实现的。我们还需要确保,当用户选择一个项目并对其进行投票时 - 如果在此期间有另一位用户进行了投票 - 我们需要重新加载文件 - 否则前一次投票将丢失。第一种锁定是悲观锁定(我们等待直到获得独占访问权),第二种是乐观锁定(如果发生冲突,我们则重新加载)。我们必须这样做 - 我们无法阻止所有其他用户 - 因为投票的用户相对来说非常慢,而读取和写入文件非常快。
  5. 除非用户已注册,否则没有简单的方法可以阻止人们重复投票。我选择使用客户端的 IP 地址,但这本身也可能导致问题,而且绝不完美(用户可以从多台机器投票,多台机器可能共享单个 IP 地址等)。另外,由于 XML 文件中可能累积大量 IP 地址,我决定在一天后删除条目。这意味着坚定的用户可以每天投票。我见过其他人使用 cookie,但同样,坚定的用户可以删除 cookie 并再次投票。因此,如果您真的需要投票是不可篡改的,那么您必须让人们以有效用户的身份登录。即使这样,如果用户可以多次注册,也可能被滥用。
  6. 我本来可以将投票存储在 SQL Server 数据库中,但我决定使用 XML 文件。这是因为并非所有托管公司都提供免费的 SQL Server 数据库。如果您想修改 VoteDataModel 使其使用数据库,应该只需要修改 Open Save 方法即可。为了更彻底地修复,可能需要对 ParseXML 进行一些重构。
  7. 我已将样式表和 JavaScript 文件包含在局部视图中。但是,这被 if (false) 包围,这意味着不会生成任何代码。包含这些文件的唯一原因是使 IntelliSense 工作。

历史

  • 2011 年 4 月 - 初始版本
© . All rights reserved.