我正在开发一个涉及帖子和评论的 ASP.NET Core MVC 项目。用户可以对帖子发表评论,也可以回复其他评论。最初的实现是有效的(检查此提交),但经过一些重构后,回复功能停止工作。现在,当我尝试回复评论时,页面只会刷新而不会点击控制器操作。
之前的工作实施:
添加评论的控制器操作:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddComment(Comment comment)
{
var user = await _userManager.GetUserAsync(User);
if (user != null)
{
comment.AuthorId = user.Id;
comment.CreatedAt = DateTime.Now;
_context.Comments.Add(comment);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Details), new { id = comment.PostId });
}
发布索引视图:
@using System.Security.Claims
@model IEnumerable<ArianNovinWeb.Models.Post>
@{
ViewData["Title"] = "Posts";
}
<div class="container">
<h1 class="mb-4">Posts</h1>
<p>
<a asp-action="Create" class="btn btn-primary">Create New Post</a>
</p>
<div class="row">
@foreach (var post in Model)
{
<div class="col-md-6 mb-4">
<div class="card">
@if (!string.IsNullOrEmpty(post.ImagePath))
{
<img src="@post.ImagePath" class="card-img-top" alt="Post Image" />
}
<div class="card-body">
<h5 class="card-title">@post.Title</h5>
<p class="card-text">@post.Description</p>
<p class="card-text"><small class="text-muted">Created by @post.Author?.UserName on @post.CreateDate.ToString("g")</small></p>
<h6>Comments</h6>
@if (post.Comments != null && post.Comments.Any())
{
@foreach (var comment in post.Comments.Where(c => c.ParentCommentId == null))
{
@await Html.PartialAsync("_CommentPartial", comment)
}
}
else
{
<p>No comments yet. Be the first to comment!</p>
}
<!-- Comment form -->
<form asp-action="AddComment" method="post" class="mt-3">
<input type="hidden" name="PostId" value="@post.PostId" />
<div class="mb-3">
<label for="Content" class="form-label">Comment:</label>
<textarea id="Content" name="Content" rows="3" class="form-control" required></textarea>
</div>
<button type="submit" class="btn btn-secondary">Add Comment</button>
</form>
<div class="mt-3 d-flex justify-content-between">
@if (User.Identity.IsAuthenticated && post.AuthorId == User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier))
{
<div>
<a asp-action="Edit" asp-route-id="@post.PostId" class="btn btn-outline-primary btn-sm">Edit</a>
<a asp-action="Delete" asp-route-id="@post.PostId" class="btn btn-outline-danger btn-sm">Delete</a>
</div>
}
<a asp-action="Details" asp-route-id="@post.PostId" class="btn btn-outline-info btn-sm">Details</a>
</div>
</div>
</div>
</div>
}
</div>
</div>
评论部分观点:
@model ArianNovinWeb.Models.Comment
<div class="card mb-2">
<div class="card-body">
<p class="card-text">@Model.Content</p>
<p class="card-text">
<small class="text-muted">
Posted by @Model.Author?.UserName on @Model.CreatedAt.ToString("g")
</small>
</p>
<!-- Reply form -->
<form asp-action="AddComment" method="post" class="mt-2">
<input type="hidden" name="PostId" value="@Model.PostId" />
<input type="hidden" name="ParentCommentId" value="@Model.CommentId" />
<div class="mb-2">
<textarea name="Content" class="form-control" rows="2" placeholder="Reply..." required></textarea>
</div>
<button type="submit" class="btn btn-secondary btn-sm">Reply</button>
</form>
<!-- Render replies recursively -->
@if (Model.Replies != null && Model.Replies.Any())
{
<div class="ml-4 mt-2">
@foreach (var reply in Model.Replies)
{
@await Html.PartialAsync("_CommentPartial", reply)
}
</div>
}
</div>
</div>
当前非工作实施:
添加评论的控制器操作:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddComment(int postId, string content, int? parentCommentId)
{
if (!ModelState.IsValid)
{
TempData["ErrorMessage"] = "Failed to add comment. Please try again.";
return RedirectToAction("Index", new { id = postId });
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return Forbid();
}
var comment = new Comment
{
PostId = postId,
Content = content,
AuthorId = user.Id,
CreatedAt = DateTime.Now,
ParentCommentId = parentCommentId
};
_context.Comments.Add(comment);
await _context.SaveChangesAsync();
TempData["SuccessMessage"] = "Comment added successfully!";
return RedirectToAction("Index", new { id = postId });
}
发布索引视图:
@using System.Security.Claims
@model ArianNovinWeb.ViewModels.PostIndexViewModel
@{
ViewData["Title"] = "Post Details";
}
<div class="container mt-4">
@if (Model.ShowShareButton)
{
<div class="text-center mt-5">
<h2>No Posts Available</h2>
<p>Be the first to share a post!</p>
<a asp-action="Create" class="btn btn-primary">Share Post</a>
</div>
}
else
{
<div class="row">
<div class="col-md-2 mt-10">
@await Html.PartialAsync("_LatestItemsPartial", Model.LatestPosts)
</div>
<div class="col-md-6">
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<a asp-action="Create" class="btn btn-primary">Share Post</a>
</div>
<div>
@if (Model.PostNavigation.PreviousPostId.HasValue)
{
<a asp-action="Index" asp-route-id="@Model.PostNavigation.PreviousPostId" class="btn btn-primary">Previous</a>
}
@if (Model.PostNavigation.NextPostId.HasValue)
{
<a asp-action="Index" asp-route-id="@Model.PostNavigation.NextPostId" class="btn btn-primary">Next</a>
}
</div>
</div>
<div class="card">
<h3 class="card-header">@Model.PostNavigation.Post.Title</h3>
<div class="card-body">
<h5 class="card-title">By: @Model.PostNavigation.Post.Author</h5>
<h6 class="card-subtitle text-muted">Posted at: @Model.PostNavigation.Post.CreateDate</h6>
</div>
@if (!string.IsNullOrEmpty(Model.PostNavigation.Post.ImagePath))
{
<img src="@Model.PostNavigation.Post.ImagePath" alt="Post Image" class="img-fluid" />
}
<div class="card-body">
<p class="card-text">@Model.PostNavigation.Post.Description</p>
</div>
<div class="mt-3 d-flex justify-content-between">
@if (User.Identity.IsAuthenticated && @Model.PostNavigation.Post.AuthorId == User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier))
{
<div>
<a asp-action="Edit" asp-route-id="@Model.PostNavigation.Post.PostId" class="btn btn-outline-primary btn-sm">Edit</a>
<a asp-action="Delete" asp-route-id="@Model.PostNavigation.Post.PostId" class="btn btn-outline-danger btn-sm">Delete</a>
</div>
}
<a asp-action="Details" asp-route-id="@Model.PostNavigation.Post.PostId" class="btn btn-outline-info btn-sm">Details</a>
</div>
</div>
<!-- Comment form -->
<div class="card mt-3 ">
<div class="card-body ">
<h3>Leave a Comment</h3>
<form asp-action="AddComment" method="post">
<input type="hidden" name="PostId" value="@Model.PostNavigation.Post.PostId" />
<div class="form-group">
<label for="Content">Comment:</label>
<textarea id="Content" name="Content" rows="4" required class="form-control"></textarea>
</div>
<button type="submit" class="btn btn-primary mt-2">Add Comment</button>
</form>
</div>
</div>
</div>
<div class="col-md-4 mt-3">
<div class="comment-section">
<h3>Comments</h3>
<!-- Display comments -->
@if (Model.PostNavigation.Post.Comments.Any())
{
@foreach (var comment in Model.PostNavigation.Post.Comments)
{
<div class="comment mb-3">
@await Html.PartialAsync("_CommentPartial", comment)
</div>
}
}
else
{
<p>No comments yet.</p>
}
</div>
</div>
</div>
}
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
<script>
$(document).ready(function () {
var successMessage = '@TempData["SuccessMessage"]';
if (successMessage) {
toastr.success(successMessage);
}
var errorMessage = '@TempData["ErrorMessage"]';
if (errorMessage) {
toastr.error(errorMessage);
}
});
</script>
}
评论部分观点:
@model ArianNovinWeb.Models.Comment
<div class="card border-primary mb-3">
<div class="card-body">
<p class="card-header">
@if (Model.Author.UserName != null)
{
<small class="text-black">
Post by @Model.Author.UserName at @Model.CreatedAt
</small>
}
else
{
<small class="text-black">
Post by @Model.Author.Email at @Model.CreatedAt
</small>
}
</p>
<p class="card-text">@Model.Content</p>
<!-- Reply form -->
<form asp-action="AddComment" method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="postId" value="@Model.PostId" />
<input type="hidden" name="parentCommentId" value="@Model.CommentId" />
<div class="mb-2">
<textarea name="content" class="form-control" rows="2" placeholder="Reply..." required></textarea>
</div>
<button type="submit" class="btn btn-secondary btn-sm">Reply</button>
</form>
<!-- Render replies recursively -->
@if (Model.Replies != null && Model.Replies.Any())
{
<div class="ml-4 mt-2">
@foreach (var reply in Model.Replies)
{
@await Html.PartialAsync("_CommentPartial", reply)
}
</div>
}
</div>
</div>
PostIndexViewModel:
using ArianNovinWeb.Models;
using ArianNovinWeb.ViewModels;
namespace ArianNovinWeb.ViewModels
{
public class PostIndexViewModel
{
public List<Post> Posts { get; set; }
public PostNavigationViewModel PostNavigation { get; set; }
public LatestItemsVM LatestPosts { get; set; }
public bool ShowShareButton { get; set; }
}
}
问题: 当我提交回复时,它会刷新帖子索引视图,但什么也没有发生。动作方法
AddComment
从未被击中,我不明白为什么。浏览器控制台中没有错误,并且表单似乎已正确发布。
问题是由于将添加评论和回复的逻辑合并到单个操作方法中,这导致了表单提交和识别的问题。这是我实施的解决方案:
添加评论和回复的单独操作方法: 我没有使用单个操作方法 (
AddComment
) 来处理评论和回复,而是为每个方法创建了单独的操作方法。
已更新
PostController
:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddComment(int postId, string content)
{
if (!ModelState.IsValid)
{
TempData["ErrorMessage"] = "Failed to add comment. Please try again.";
return RedirectToAction("Index", new { id = postId });
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return Forbid();
}
var comment = new Comment
{
PostId = postId,
Content = content,
AuthorId = user.Id,
CreatedAt = DateTime.Now
};
_context.Comments.Add(comment);
await _context.SaveChangesAsync();
TempData["SuccessMessage"] = "Comment added successfully!";
return RedirectToAction("Index", new { id = postId });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddReply(int postId, string content, int parentCommentId)
{
if (!ModelState.IsValid)
{
TempData["ErrorMessage"] = "Failed to add reply. Please try again.";
return RedirectToAction("Index", new { id = postId });
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return Forbid();
}
var reply = new Comment
{
PostId = postId,
Content = content,
AuthorId = user.Id,
CreatedAt = DateTime.Now,
ParentCommentId = parentCommentId
};
_context.Comments.Add(reply);
await _context.SaveChangesAsync();
TempData["SuccessMessage"] = "Reply added successfully!";
return RedirectToAction("Index", new { id = postId });
}
更新了评论部分视图以使用新的
AddReply
操作方法:
@model ArianNovinWeb.Models.Comment
<div class="card border-primary mb-3">
<div class="card-body">
<p class="card-header">
@if (Model.Author.UserName != null)
{
<small class="text-black">
Post by @Model.Author.UserName at @Model.CreatedAt
</small>
}
else
{
<small class="text-black">
Post by @Model.Author.Email at @Model.CreatedAt
</small>
}
</p>
<p class="card-text">@Model.Content</p>
<!-- Reply form -->
<form asp-action="AddReply" method="post" class="mt-2">
@Html.AntiForgeryToken()
<input type="hidden" name="PostId" value="@Model.PostId" />
<input type="hidden" name="ParentCommentId" value="@Model.CommentId" />
<div class="mb-2">
<textarea name="content" class="form-control" rows="2" placeholder="Reply..." required></textarea>
</div>
<button type="submit" class="btn btn-secondary btn-sm">Reply</button>
</form>
<!-- Render replies recursively -->
@if (Model.Replies != null && Model.Replies.Any())
{
<div class="ml-4 mt-2">
@foreach (var reply in Model.Replies)
{
@await Html.PartialAsync("_CommentPartial", reply)
}
</div>
}
</div>
</div>
现在效果很好。