我有一种简单(可能粗略)的方式来审核我正在构建的博客上的评论。这是一个学习/有趣的项目,所以我自己动手一切,以便更熟悉一些不同的技术。我想知道我的逻辑中是否存在任何漏洞,或者可能是我正在做的更好的实现。我将允许在网站上进行匿名评论,但我想对他认为不合适的任何内容进行调整。我是这样做的:
我的模型使用EF Code第一种方法:
public class Comment
{
public int Id { get; set; }
public bool Moderated { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
}
标准的东西在这里。然后我创建了一个ViewModel来显示博客文章的详细信息以及与页面相关的所有评论,如下所示:
public class PostCommentViewModel
{
public Post Post { get; set; }
public List<Comment> Comment { get; set; }
public PostCommentViewModel(int postId)
{
var db = new BlogContext();
Post = db.Posts.First(x => x.Id == postId);
var query = from x in db.Comments where x.PostId == postId && x.Moderated == true select x;
Comment = query.ToList();
}
}
对于评论,这只是抓住与PostId相关并且已经过审核的评论(即我能够审核它们)
对于显示此视图的视图,我只使用基础脚手架模板:
public ActionResult Details(int id = 0)
{
var viewModel = new PostCommentViewModel(id);
return View(viewModel);
}
cshtml:
@model CodeFirstBlog.ViewModels.PostCommentViewModel
<fieldset>
<legend>PostCommentViewModel</legend>
@Html.DisplayFor(x => x.Post.Title)
<br />
@Html.DisplayFor(x => x.Post.Content)
<br />
@Html.DisplayFor(x => x.Post.CreatedDate)
<hr />
@foreach(var comment in Model.Comment)
{
@Html.DisplayFor(x => comment.Content)
<br />
@Html.DisplayFor(x => comment.DateCreated)
<br />
@Html.DisplayFor(x => comment.DisplayName)
<br />
@Html.DisplayFor(x => comment.Email)
<br />
<hr />
}
</fieldset>
@Html.ActionLink("Add Comment", "AddComment", new { id = Model.Post.Id} )
这是Controller中的AddComment
public ActionResult AddComment(int id = 0)
{
return View();
}
[HttpPost]
public ActionResult AddComment(Comment comment, int id)
{
if (ModelState.IsValid)
{
comment.PostId = id;
db.Comments.Add(comment);
db.SaveChanges();
return RedirectToAction("Details", "Blog", new { id = id });
}
return RedirectToAction("Details", "Blog", new { id = id });
}
因此,当我添加评论时,Moderated默认为false,因此评论不会立即显示。现在,如果管理员登录,他可以转到ViewModeration视图,该视图只返回等待批准的所有评论的列表:
public ActionResult ViewModeration()
{
var comments = from x in db.Comments where x.Moderated == false select x;
return View(comments);
}
如果他点击批准按钮,它会在控制器中执行:
public ActionResult ApproveComment(int id)
{
Comment c = (from x in db.Comments
where x.Id == id
select x).First();
c.Moderated = true;
db.SaveChanges();
return RedirectToAction("ViewModeration");
}
我真正想知道的是:
答案 0 :(得分:4)
到目前为止,该模型似乎暂缓了,所以我将以这种方式回答这个问题:
此实现中是否存在任何漏洞,例如知道用户是否可以覆盖回发中的仲裁值?
是。我不知道任何基于你发送的内容的FORM代码,但我假设你是通过post值创建一个Comment并直接保存到数据库。这可能很糟糕。最好只从用户那里获得所需的值,并将其余部分填入控制器中:
public ActionResult AddComment(Comment comment, int id)
{
if (ModelState.IsValid)
{
// NEW
comment.Moderated = false;
comment.PostId = id;
db.Comments.Add(comment);
db.SaveChanges();
return RedirectToAction("Details", "Blog", new { id = id });
}
return RedirectToAction("Details", "Blog", new { id = id });
}
是否有更简单或更优雅的解决方案可供遵循?我再次不想使用任何预先构建的东西。这个项目的目的是学习东西。
如前所述,到目前为止这看起来还不错。但是,为了可重用性和测试目的,我可能会在不同的类中使用数据库操作,例如服务或存储库。
所以,代码看起来像这样:
public ActionResult AddComment(Comment comment, int id)
{
if (ModelState.IsValid)
{
CommentService.Save(comment);
return RedirectToAction("Details", "Blog", new { id = id });
}
return RedirectToAction("Details", "Blog", new { id = id });
}
这不是一个很大的改变,但如果你想重用这段代码,它会让你在以后获得更大的灵活性。
至于你的PostCommentViewModel类,我没有在ViewModel中做任何操作,特别是在构造函数中没有。你应该使用ViewModels的方法是将数据绑定到它而不是让ViewModel完成这项工作。您可以从中获取数据,ViewModel仅表示需要显示的结构。因此,从那里获取代码,并将其放在服务中(即:CommentService)。
答案 1 :(得分:2)
第一个问题的答案是是,知道用户可以设置Moderated
值。不久前GitHub也发生了类似的事情。有关完整说明,请参阅this post。简短的解释是,用户可以在Chrome Developer Tools之类的内容中修改表单数据,并在发布之前在模型上设置Moderated
属性。
要回答你的第二个问题,我可以看到两个选项(其他请注释,如果你知道更多)
1)您可以调用DefaultModelBinder
并仅指定应更新的属性,而不是让Comment
将值绑定到您的TryUpdateModel
模型。 E.g。
public ActionResult AddComment(int id)
{
if (ModelState.IsValid)
{
Comment comment = new Comment();
TryUpdateModel(comment, new[] { "Email ", "DateCreated", "Content", "etc" });
comment.PostId = id;
db.Comments.Add(comment);
...
}
...
}
2)更好的选择imho是创建一个单独的模型类,它甚至不包含Moderated
属性,并使用此模型进行用户注释。您可以将现有的Comment
模型用于仅供管理员访问的操作的管理目的。