我正在尝试添加表单,以允许用户对我的博客应用程序上的帖子发表评论。到目前为止,我已经在帖子详细信息视图中添加了一个表单,我可以提交注释,将它们正确添加到我的数据库中。但是,我在向用户显示验证错误时遇到问题。注释表单包含在局部视图中,并使用帖子详细信息视图中的Html.RenderAction
进行呈现。我想强调一点,我不想使用AJAX,因为我想从渐进式增强的角度来看待它。
以下是相关的发布操作:
[HttpPost, Authorize]
public ActionResult AddComment(CommentViewModel newComment)
{
if (ModelState.IsValid)
{
Comment comment = new Comment(_userRepository.GetByUsername(User.Identity.Name));
Mapper.Map(newComment, comment);
_commentRepository.Add(comment);
_postsRepository.CommentAdded(comment.Article);
return RedirectToAction("Index", new { id = newComment.PostID });
}
// What do I do here?
}
我已经尝试了几种返回视图的方法,但是我在父操作中进行的一些控制器参数验证使我的问题更加复杂:
//
// GET: /Posts/5/this-is-a-slug
public ActionResult Index(int id, string slug)
{
PostViewModel viewModel = new PostViewModel();
var model = _postsRepository.GetByID(id);
if (model != null)
{
if (slug == null || slug.CompareTo(model.Slug) != 0)
{
return RedirectToActionPermanent("Index", new { id, slug = model.Slug });
}
else
{
_postsRepository.PostVisited(model);
Mapper.Map(model, viewModel);
viewModel.AuthorName = _userRepository.GetById(model.AuthorID);
}
}
return View(viewModel);
}
此操作基本上模仿了SO的URL如何工作。如果提供了帖子ID,则会从数据库中提取帖子以及创建帖子时创建的slug。如果URL中的slug与数据库中的slug不匹配,则重定向以包含slug。这很好用,但它确实意味着我在尝试填充我的父视图模型时遇到问题,如下所示:
public class PostViewModel
{
public int PostID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Slug { get; set; }
public DateTime DatePublished { get; set; }
public int NumberOfComments { get; set; }
public int AuthorID { get; set; }
public string AuthorName { get; set; }
public List<CommentViewModel> Comments { get; set; }
public CommentViewModel NewComment { get; set; }
}
我希望能够工作的是填充PostViewModel.NewComment
,测试它是否有数据然后用它来显示任何模型错误。不幸的是,我失去了如何实现这一目标。 This question帮助我塑造了我的方法,但它并没有完全解决我的问题。
有人能给我一个正确的方向吗?如果我的方法看起来不合理,我很想知道为什么以及可能的解决方案。
非常感谢提前。
答案 0 :(得分:2)
忘了在这里填写我的答案。对于碰巧遇到此问题的任何人,答案是使用TempData
来存储ModelState
错误,然后在相关控制器操作中重新填充ModelState
。
首先,我在控制器中声明了一个用于引用TempData
内部数据的键。我决定将其基于CommentViewModel
类型,因为两个操作都取决于它。
public class PostsController : Controller
{
private static readonly string commentFormModelStateKey = typeof(CommentViewModel).FullName;
// Rest of class.
}
在第一个操作中,代码会检查TempData
是否包含分配给密钥的数据。如果是,则将其复制到ModelState
。
// GET: /posts/comment
[ChildActionOnly]
public PartialViewResult Comment(PostViewModel viewModel)
{
viewModel.NewComment = new CommentViewModel(viewModel.PostID, viewModel.Slug);
if (TempData.ContainsKey(commentFormModelStateKey))
{
ModelStateDictionary commentModelState = TempData[commentFormModelStateKey] as ModelStateDictionary;
foreach (KeyValuePair<string, ModelState> valuePair in commentModelState)
ModelState.Add(valuePair.Key, valuePair.Value);
}
return PartialView(viewModel.NewComment);
}
此操作确定在向数据库添加注释之前ModelState
是否有效。如果ModelState
无效,则会将其复制到TempData
,这使其可用于第一个操作。
// POST: /posts/comment
[HttpPost, Authorize]
public ActionResult Comment(CommentViewModel newComment)
{
if (!ModelState.IsValid)
{
TempData.Add(commentFormModelStateKey, ModelState);
return Redirect(Url.ShowPost(newComment.PostID, newComment.Slug));
}
// Code to add a comment goes here.
}