ASP.NET 核心 MVC - Ajax Post 请求 400 错误
ASP.NET Core MVC - Ajax Post Request 400 Error
在 ajax 中,如果我写:data: JSON.stringify(cat)
我得到这个错误:The JSON value could not be converted to System.Collections.Generic.IEnumerable
如果我写:data: cat
我得到这个错误:'i' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
所以,我想我在 json 上做错了什么,但是什么?
以下是类别的相关 类:
Area.Identity.Data.Category:
public class Category
{
//----------------------------------------------------
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//----------------------------------------------------
public string Name { get; set; }
//----------------------------------------------------
public ICollection<Post> Posts { get; set; }
public Category(string name)
{
Name = name;
}
}
Models.Category:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public Category(int id, string name)
{
Id = id;
Name = name;
}
}
CategoryMapper.cs:
public class CategoryMapper
{
public static Models.Category FromDatabase(Areas.Identity.Data.Category cat)
{
return new Models.Category
(
cat.Id,
cat.Name
);
}
public static Areas.Identity.Data.Category ToDatabase(Models.Category cat)
{
return new Areas.Identity.Data.Category
(
//id is database generated
cat.Name
);
}
}
CategoryRepository.cs:
public class CategoryRepository
{
private readonly MyContext _context;
public CategoryRepository(MyContext context)
{
_context = context;
}
public IEnumerable<Models.Category> GetAll()
{
return _context.Category.Select(x => CategoryMapper.FromDatabase(x));
}
public void Save(Models.Category category)
{
_context.Category.Add(CategoryMapper.ToDatabase(category));
_context.SaveChanges();
}
}
CategoryService.cs:
public class CategoryService
{
private CategoryRepository _catRepository;
public CategoryService(CategoryRepository catRepository)
{
_catRepository = catRepository;
}
public IEnumerable<Models.Category> GetAll()
{
return _catRepository.GetAll();
}
public void Save(Models.Category cat)
{
_catRepository.Save(cat);
}
}
CategoryController.cs:
public class CategoryController : Controller
{
// GET: Category
public ActionResult Index()
{
return View();
}
// GET: Category/Details/5
public ActionResult Details(int id)
{
ViewBag.ID = id;
return View();
}
// GET: Category/Create
public ActionResult Create()
{
return View();
}
// POST: Category/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
return View();
}
}
CategoryApiController.cs:
[Route("api/category")]
[ApiController]
public class CategoryApiController : ControllerBase
{
private CategoryService _catService;
public CategoryApiController(CategoryService catService)
{
_catService = catService;
}
[HttpGet]
public ActionResult<List<Models.Category>> Get()
{
return _catService.GetAll().ToList();
}
[HttpGet("{id}")] // api/category/0
public ActionResult<Models.Category> Get(int id)
{
return _catService.GetAll().ToList().Find(x => x.Id == id);
}
[HttpPost]
//[Route("/api/category/save")]
public IActionResult Save([FromBody] JObject json)
{
Models.Category c= CategoryDto.FromJson(json);
_catService.Save(c);
return Ok();
}
}
CategoryDto.cs:
public static class CategoryDto
{
public static Models.Category FromJson(JObject json)
{
var id = json["id"].ToObject<int>();
var name = json["name"].ToObject<string>();
return new Models.Category(id, name);
}
}
Create.cshtml:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<h2>Create New Category </h2>
<table id="table">
<thead id="table-head"></thead>
<tbody id="table-body"></tbody>
</table>
<form class="AddCategory">
<div class="form-group">
<div class="form-group">
<input required="" id="cat_input" class="form-control" />
<span class="text-danger"></span>
</div><!-- .form-group -->
<div class="form-group">
<label>Input category name:</label>
<input type="button" value="Add new category value" class="btn btn-primary addCategory" />
</div><!-- .form-group -->
</div><!-- .form-group -->
</form>
<script type="text/javascript">
'use strict';
function createRow(JsonObj) {
let row = document.createElement('tr');
let cellId = document.createElement('td');
cellId.innerHTML = JsonObj.id;
let cellName = document.createElement('td');
cellName.innerHTML = JsonObj.name;
row.appendChild(cellId);
row.appendChild(cellName);
return row;
}
function createHeader(JsonObj) {
let keys = Object.keys(JsonObj);
let row = document.createElement('tr');
for (let i = 0; i < keys.length; i++) {
const item = keys[i];
var cell = document.createElement('th');
cell.innerHTML = item;
row.appendChild(cell);
}
return row;
}
async function getAll() {
return await axios.get('/api/category');
}
function afterGetAll(response) {
console.log(response.data);
document.getElementById('table-head').appendChild(createHeader(response.data[0]));
for (let i = 0; i < response.data.length; i++) {
const item = response.data[i];
document.getElementById('table-body').appendChild(createRow(item));
}
//Add New Category
$('.addCategory').on('click', function () {
var cat_input = $('#cat_input').val();
var _id = parseInt(response.data.length + 1);
var cat = { id: _id, name: cat_input };
console.log(cat);
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: '/api/category',
dataType: 'json',
data: JSON.stringify(cat),
/*beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},*/
headers: {
"RequestVerificationToken": '@GetAntiXsrfRequestToken()'
},
success: function () {
console.log('ok');
},
error: function () {
console.log('not ok');
}
});
});
}
$(document).ready(function () {
getAll().then(response => afterGetAll(response));
});
</script>
JObject
适用于ASP.NET Core 3 之前的版本,如果你想在3.0 或更高版本中使用它,你必须下载软件包:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.6
在 Startup.cs
中启用它
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson();
}
在 ajax 中,如果我写:data: JSON.stringify(cat)
我得到这个错误:The JSON value could not be converted to System.Collections.Generic.IEnumerable
如果我写:data: cat
我得到这个错误:'i' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
所以,我想我在 json 上做错了什么,但是什么?
以下是类别的相关 类:
Area.Identity.Data.Category:
public class Category
{
//----------------------------------------------------
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//----------------------------------------------------
public string Name { get; set; }
//----------------------------------------------------
public ICollection<Post> Posts { get; set; }
public Category(string name)
{
Name = name;
}
}
Models.Category:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public Category(int id, string name)
{
Id = id;
Name = name;
}
}
CategoryMapper.cs:
public class CategoryMapper
{
public static Models.Category FromDatabase(Areas.Identity.Data.Category cat)
{
return new Models.Category
(
cat.Id,
cat.Name
);
}
public static Areas.Identity.Data.Category ToDatabase(Models.Category cat)
{
return new Areas.Identity.Data.Category
(
//id is database generated
cat.Name
);
}
}
CategoryRepository.cs:
public class CategoryRepository
{
private readonly MyContext _context;
public CategoryRepository(MyContext context)
{
_context = context;
}
public IEnumerable<Models.Category> GetAll()
{
return _context.Category.Select(x => CategoryMapper.FromDatabase(x));
}
public void Save(Models.Category category)
{
_context.Category.Add(CategoryMapper.ToDatabase(category));
_context.SaveChanges();
}
}
CategoryService.cs:
public class CategoryService
{
private CategoryRepository _catRepository;
public CategoryService(CategoryRepository catRepository)
{
_catRepository = catRepository;
}
public IEnumerable<Models.Category> GetAll()
{
return _catRepository.GetAll();
}
public void Save(Models.Category cat)
{
_catRepository.Save(cat);
}
}
CategoryController.cs:
public class CategoryController : Controller
{
// GET: Category
public ActionResult Index()
{
return View();
}
// GET: Category/Details/5
public ActionResult Details(int id)
{
ViewBag.ID = id;
return View();
}
// GET: Category/Create
public ActionResult Create()
{
return View();
}
// POST: Category/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
return View();
}
}
CategoryApiController.cs:
[Route("api/category")]
[ApiController]
public class CategoryApiController : ControllerBase
{
private CategoryService _catService;
public CategoryApiController(CategoryService catService)
{
_catService = catService;
}
[HttpGet]
public ActionResult<List<Models.Category>> Get()
{
return _catService.GetAll().ToList();
}
[HttpGet("{id}")] // api/category/0
public ActionResult<Models.Category> Get(int id)
{
return _catService.GetAll().ToList().Find(x => x.Id == id);
}
[HttpPost]
//[Route("/api/category/save")]
public IActionResult Save([FromBody] JObject json)
{
Models.Category c= CategoryDto.FromJson(json);
_catService.Save(c);
return Ok();
}
}
CategoryDto.cs:
public static class CategoryDto
{
public static Models.Category FromJson(JObject json)
{
var id = json["id"].ToObject<int>();
var name = json["name"].ToObject<string>();
return new Models.Category(id, name);
}
}
Create.cshtml:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<h2>Create New Category </h2>
<table id="table">
<thead id="table-head"></thead>
<tbody id="table-body"></tbody>
</table>
<form class="AddCategory">
<div class="form-group">
<div class="form-group">
<input required="" id="cat_input" class="form-control" />
<span class="text-danger"></span>
</div><!-- .form-group -->
<div class="form-group">
<label>Input category name:</label>
<input type="button" value="Add new category value" class="btn btn-primary addCategory" />
</div><!-- .form-group -->
</div><!-- .form-group -->
</form>
<script type="text/javascript">
'use strict';
function createRow(JsonObj) {
let row = document.createElement('tr');
let cellId = document.createElement('td');
cellId.innerHTML = JsonObj.id;
let cellName = document.createElement('td');
cellName.innerHTML = JsonObj.name;
row.appendChild(cellId);
row.appendChild(cellName);
return row;
}
function createHeader(JsonObj) {
let keys = Object.keys(JsonObj);
let row = document.createElement('tr');
for (let i = 0; i < keys.length; i++) {
const item = keys[i];
var cell = document.createElement('th');
cell.innerHTML = item;
row.appendChild(cell);
}
return row;
}
async function getAll() {
return await axios.get('/api/category');
}
function afterGetAll(response) {
console.log(response.data);
document.getElementById('table-head').appendChild(createHeader(response.data[0]));
for (let i = 0; i < response.data.length; i++) {
const item = response.data[i];
document.getElementById('table-body').appendChild(createRow(item));
}
//Add New Category
$('.addCategory').on('click', function () {
var cat_input = $('#cat_input').val();
var _id = parseInt(response.data.length + 1);
var cat = { id: _id, name: cat_input };
console.log(cat);
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: '/api/category',
dataType: 'json',
data: JSON.stringify(cat),
/*beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},*/
headers: {
"RequestVerificationToken": '@GetAntiXsrfRequestToken()'
},
success: function () {
console.log('ok');
},
error: function () {
console.log('not ok');
}
});
});
}
$(document).ready(function () {
getAll().then(response => afterGetAll(response));
});
</script>
JObject
适用于ASP.NET Core 3 之前的版本,如果你想在3.0 或更高版本中使用它,你必须下载软件包:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.6
在 Startup.cs
中启用它public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson();
}