【问题标题】:Posting to Web API Controller from Razor Page Always Returns 400 Error从 Razor 页面发布到 Web API 控制器总是返回 400 错误
【发布时间】:2021-11-02 16:52:54
【问题描述】:

我是 .Net Core 和 MVC 的新手。我有几个 Razor 页面,允许用户发布诸如 cmets 和单个帖子的评级之类的东西,但我想尝试一些新的东西来喜欢一个帖子,这样就可以使用 javascript 完成它而无需刷新页面。为此,我尝试使用 jQuery ajax 通过 API 控制器将数据从页面传递到服务类。不幸的是,每次我尝试将一个简单的值传递给控制器​​时,我都会收到一个错误 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";
            }
            
        }

我在 Razor 页面中的 jQuery 如下所示:

<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 文件),所以我不得不出去寻找一个可能实际可行的解决方案现实世界。

【问题讨论】:

    标签: asp.net asp.net-core asp.net-core-webapi


    【解决方案1】:

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

    主体是一个具有名为postId 的属性的对象。因此,尝试将其定义为您的 DTO:

    public sealed class AddPostLikePostDto
    {
      public int PostId { get; set; }
    }
    
    ...
    
    public async Task<string> AddPostLike([FromBody] AddPostLikePostDto dto)
    

    【讨论】:

    • 终于帮我插入了一条记录,但是成功的功能没用。该页面几乎一直在加载,就像点击了刷新按钮一样,并且喜欢计数永远不会更新。另一个问题似乎是来自控制器的响应,如果用户没有按照应有的方式登录,控制器永远不会告诉人们他们必须登录。无论是否添加类似,任务都不会返回字符串。
    【解决方案2】:

    如果您只想发布整数数据,只需更改如下:

    data: JSON.stringify(postid)
    

    但是成功功能不起作用。

    那是因为计数器没有增加,你可以使用likecount++likecount = likecount + 1使其工作。

    另一个问题似乎是来自控制器的响应,如果用户没有按应有的方式登录,控制器从不告诉人们他们必须登录。

    那是因为你后端的 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");
        }
    
    }
    

    【讨论】:

    • 谢谢。这真的很好用。我将不得不进行一些更改,但就基本上能够传递价值而言,它的效果很好。
    • 响应OK时如何通过success函数访问返回值?
    • 只需执行以下操作:success: function (data) {console.log(data);}
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-01-01
      • 2015-02-25
      • 2018-06-30
      • 1970-01-01
      • 2019-04-27
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      相关资源
      最近更新 更多