ASP.NET Core MVC:重构后评论回复不起作用

问题描述 投票:0回答:1

我正在开发一个涉及帖子和评论的 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
从未被击中,我不明白为什么。浏览器控制台中没有错误,并且表单似乎已正确发布。

c# asp.net-core-mvc
1个回答
0
投票

问题是由于将添加评论和回复的逻辑合并到单个操作方法中,这导致了表单提交和识别的问题。这是我实施的解决方案:

添加评论和回复的单独操作方法: 我没有使用单个操作方法 (

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>

现在效果很好。

© www.soinside.com 2019 - 2024. All rights reserved.