从 Razor 页面发布到 Web API 控制器总是 Returns 400 错误

Posting to Web API Controller from Razor Page Always Returns 400 Error

我是 .Net Core 和 MVC 的新手。我有几个 Razor 页面,允许用户 post 诸如个人 post 的评论和评级之类的东西,但我想尝试一些新的东西来喜欢 post,这样它就可以在不刷新页面的情况下使用 javascript 完成。为此,我尝试使用 jQuery ajax 通过 API 控制器将数据从页面传递到服务 class。不幸的是,每次我尝试将一个简单的值传递给控制器​​时,我都会收到错误 400,指出该值无法转换为 System.WhateverObjectTypeITry。例如,如果我尝试将它作为整数传递,我得到“JSON 值无法转换为 System.Int32”,如果我尝试将它作为字符串传递,我得到“JSON 值无法转换为 System.String"

我的 API 控制器看起来像这样:

[HttpPost]
        [Route("AddPostLike")]
        public async Task<string> AddPostLike([FromBody] int postid)
        {
            if(_signInManager.IsSignedIn(User))
            {
                ApplicationUser user = await _userManager.GetUserAsync(User);
                Likes newLike = new Likes();
                newLike.Post = Convert.ToInt32(postid);
                newLike.Commentid = null;
                newLike.Userid = user.Id;
                await _likeService.LikeAsync(newLike);
                return $"liked";
            }
            else
            {
                return $"User Must Be Logged in to Like";
            }
            
        }

我的 jQuery 在 Razor 页面中看起来像这样:

<script>
         $(document).ready(function () {
             $('#like-post').on('click', function () {
                 var postid = parseInt($('#idlabel').text());
                 $.ajax({
                     url: '/api/Likes/AddPostLike/',
                     type: 'POST',
                     dataType: 'text',
                     data: '{"postid":"' + postid + '"}',
                     contentType: 'application/json',
                     success: function () {
                         var likecount = parseInt($('#like-post-count').text());
                         likecount + 1;
                         $('#like-post-count').text(likecount);
                     },
                     error: function (XMLHttpRequest, textStatus, errorThrown) {
                         alert("responseText=" + XMLHttpRequest.responseText + "\n textStatus=" + textStatus + "\n errorThrown=" + errorThrown);
                     }
        });
             });


    });
    </script>

我正在使用 .Net Core 5.0 并尝试使用 Contoso Crafts 演示作为指南,但构建 Contoso Crafts 的 Microsoft 人员决定使用 Blazor 组件而不是剃须刀页面,后者以某种方式与控制器通信尽管不要求开发人员编写任何 javascript(参见 https://github.com/dotnet-presentations/ContosoCrafts/blob/master/src/Components/ProductList.razor)并且他们不使用数据库来存储数据(他们使用静态 JSON 文件),所以我有走出去寻找可能在现实世界中实际起作用的解决方案。

您的 [FromBody] 属性表示正文应该可以解析为整数,但正文实际上类似于 {"postid":"13"}.

正文是一个带有 属性 名为 postId 的对象。因此,请尝试将其定义为您的 DTO:

public sealed class AddPostLikePostDto
{
  public int PostId { get; set; }
}

...

public async Task<string> AddPostLike([FromBody] AddPostLikePostDto dto)

除了修复数据发送到控制器的方式(@StephenCleary 已经提供了一种可能的方式),您还必须通过添加结果参数来修复成功函数

 success: function (result) {
 var likecount = parseInt(result).text());
 likecount + 1;
 $('#like-post-count').text(likecount);
 },

如果你只想post一个整数数据,只需像下面这样改变:

data: JSON.stringify(postid)

but the success function did not work.

那是因为计数器不增加,可以用likecount++likecount = likecount + 1来使它起作用。

Another problem seems to be with the response from the controller which never tells people they must be logged in if the user is not signed in like it should.

那是因为你后端的 else 子句是对 ajax 的正确响应,你可以简单地抛出一个异常 比如:throw new Exception("User Must Be Logged in to Like");

另一种方式,您可以像下面这样更改您的代码:

[HttpPost]
[Route("AddPostLike")]
public async Task<IActionResult> AddPostLike([FromBody] int postid)
{
    if (xxx)
    {
        return Ok("liked");
    }
    else
    {
        //return $"User Must Be Logged in to Like";
        return BadRequest("User Must Be Logged in to Like");
    }
}

整个工作演示:

<label id="idlabel">1</label>
<label id="like-post-count" >4</label>
<input id="like-post" type="button" value="Post"/>
@section Scripts
{
    <script>
        $(document).ready(function () {
            $('#like-post').on('click', function () {
                var postid = parseInt($('#idlabel').text());
                $.ajax({
                    url: '/api/Likes/AddPostLike/',
                    type: 'POST',
                    dataType: 'text',
                    data: JSON.stringify(postid),    //change here....
                    contentType: 'application/json',
                    success: function () {
                        var likecount = parseInt($('#like-post-count').text());
                        likecount++;
                        $('#like-post-count').text(likecount);
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert("responseText=" + XMLHttpRequest.responseText + "\n textStatus=" + textStatus + "\n errorThrown=" + errorThrown);
                    }
                });
            });
        });
    </script>
}

控制器:

[HttpPost]
[Route("AddPostLike")]
public async Task<string> AddPostLike([FromBody] int postid)
{
    if (xxxx)
    {
        return $"liked";
    }
    else
    {
        //return $"User Must Be Logged in to Like";
        throw new Exception("User Must Be Logged in to Like");
    }

}