【问题标题】:JSON serializer writes excessive ']'JSON 序列化程序写入过多的 ']'
【发布时间】:2021-01-01 19:55:34
【问题描述】:

我有一个 API 控制器,它接受 HTTP 请求并返回一些结果。一切正常,但是当它收到PUT请求时,序列化程序会使用过多的']'写入数据,所以当我想从JSON文件中获取数据时,程序会返回错误。

控制器 API 代码:

using Gazda.Models;
using Gazda.Services;
using Microsoft.AspNetCore.Mvc;
using System;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace Gazda.Controllers
{
    [Route("/api/Comment")]
    [ApiController]
    public class CommentController : Controller
    {
        public CommentController(JsonFileCommentService jsonFileCommentService)
        {
            JsonFileCommentService = jsonFileCommentService;
        }
        public JsonFileCommentService JsonFileCommentService { get;}

        [HttpPost]
        public IActionResult Post([FromForm]Comment comment)
        {

            comment.Id = Guid.NewGuid().ToString();

            JsonFileCommentService.AddComment(comment);

            return Ok(comment);
        }

        [HttpGet]
        public JsonResult Get()
        {
            var comments = JsonFileCommentService.GetComments();
            return Json(comments);
        }

        [HttpPut]
        public IActionResult Put([FromBody] string id)
        {
            JsonFileCommentService.ChangeLike(id);
            return Ok("Successfull PUT");
        }

    }
}

PUT 请求之前的 JSON 文件:

[
  {
    "Id": "9d2a1e79-cd44-43a0-88cd-0d8868cd723e",
    "Name": "Yurii",
    "Text": "\u043D\u0430\u0434\u0437\u0432\u0438\u0447\u0430\u0439\u043D\u043E \u0441\u043C\u0430\u0447\u043D\u043E",
    "isLiked": false
  },
  {
    "Id": "e8577368-9634-40cc-ba30-7e3efd8f7ec3",
    "Name": "Arch",
    "Text": "super taste",
    "isLiked": true
  }
]

PUT 请求后的 JSON 文件:

[
  {
    "Id": "9d2a1e79-cd44-43a0-88cd-0d8868cd723e",
    "Name": "Yurii",
    "Text": "\u043D\u0430\u0434\u0437\u0432\u0438\u0447\u0430\u0439\u043D\u043E \u0441\u043C\u0430\u0447\u043D\u043E",
    "isLiked": false
  },
  {
    "Id": "e8577368-9634-40cc-ba30-7e3efd8f7ec3",
    "Name": "Arch",
    "Text": "super taste",
    "isLiked": false
  }
]]

服务代码:

using Gazda.Models;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;

namespace Gazda.Services
{
    public class JsonFileCommentService
    {
        public JsonFileCommentService(IWebHostEnvironment webHostEnvironment)
        {
            WebHostEnvironment = webHostEnvironment;
        }
        
        IWebHostEnvironment WebHostEnvironment { get; set; }

        private string JsonFileName
        {
            get { return Path.Combine(WebHostEnvironment.WebRootPath, "data", "comments.json"); }
        }

        private void SerializeComments(List<Comment> comments)
        {
            using (var outputStream = File.OpenWrite(JsonFileName))
            {
                JsonSerializer.Serialize<IEnumerable<Comment>>(
                    new Utf8JsonWriter(outputStream, new JsonWriterOptions
                    {
                        SkipValidation = true,
                        Indented = true
                    }), comments);
            }
        }
        
        public List<Comment> GetComments()
        {
            try
            {
                using (var jsonFileReader = File.OpenText(JsonFileName))
                {
                    return JsonSerializer.Deserialize<List<Comment>>(jsonFileReader.ReadToEnd(),
                        new JsonSerializerOptions
                        {
                            PropertyNameCaseInsensitive = true
                        });
                }
            }
            catch
            {
                return new List<Comment>();
            }
        }

        public void AddComment(Comment comment)
        {
            if(comment==null)
            {
                throw new ArgumentNullException();
            }

            var comments = GetComments();

            comments.Add(comment);

            SerializeComments(comments);
        }

        public void ChangeLike(string id)
        {
            var comments = GetComments();

            var comment = comments.First(x=> x.Id == id);

            comment.isLiked = !comment.isLiked;

            SerializeComments(comments);
        }
    }
}

最有趣的是,当控制器收到 POST 请求时,该服务会清楚地序列化数据。所以,我不明白,为什么会这样。 提前谢谢!!!

附:有关更多信息,这里是我的 React 代码,我在其中提出了 put 请求:

import React, { Component } from 'react'
import axios from 'axios';

export default class Comment extends Component {
    constructor(props){
        super(props);

        this.click = this.click.bind(this);
    }
    
    click(event){
        event.target.classList.toggle("likes");
        console.log(this.props.comment.id)
        axios({
            method: 'PUT',
            url: '/api/Comment', 
            data: JSON.stringify(this.props.comment.id), 
            headers:{'Content-Type': 'application/json; charset=utf-8'}
        })    
             .then(resp=>console.log(resp.data))
             .catch((err) => { throw err });
    }

    componentDidMount(){
        console.log("I'm inside component")
    }

    render() {
        return (
            <div>
                <div className="comment-item">
                    <div className="comment-name">{this.props.comment.name}: 
            </div>
                    <div className="comment-text">{this.props.comment.text}</div>
                    <i className="fas fa-heart" onClick={this.click}></i>
                    
                </div>
            </div>
        )
    }
}

【问题讨论】:

  • 很有趣,但我认为重现此行为的最小示例会非常有帮助。

标签: c# json asp.net-web-api


【解决方案1】:

为确保输出文件的全部内容被覆盖,您应该使用以下命令打开文件:

var outputStream = File.Open(JsonFileName, FileMode.Create)  

当通过File.OpenWrite 打开时,它会更新其内容;但只有更新数据中存在的字符数量会发生变化。
当原始数据有更多字符时,这些多余的字符仍保留在此文件中。


来自File.OpenWrite documentation

对于现有文件,它不会将新文本附加到现有文件中 文本。
相反,它会用新的字符覆盖现有字符 字符。
如果覆盖较长的字符串(例如“This is a test of the OpenWrite method”)
对于较短的字符串(例如“Second run”),该文件将包含多个字符串(“Second runtest of the OpenWrite method”)。

【讨论】:

  • 唯一让我困惑的部分是 OP 声称文件内容长了 1 个字节(true -> false),但出现了一个额外的括号。我可以理解内容是否缩短了 1 个字节.. ?‍♀️
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多