jQuery Ajax/JSON 使用 .Net 6 MVC 模型投标序列化上传文件
Upload files using .Net 6 MVC model biding serialization by jQuery Ajax/JSON
需要通过 AJAX jQuery/JSON.
使用 MVC 模型投标上传文件
我之前使用的是正常的提交表单,但现在我需要更改为 AJAX。
我怎样才能做到这一点?我的意思是,使用 MVC 和 AJAX 进行投标,序列化我的表格或类似的东西。
现在,我的控制器上的 imagemPro 和 imagemPre 总是 'null'。
在我看来:
@model Ri.Models.Produto
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="@Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="@Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="@Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="@Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
@section scripts{
<script src="~/admin/js/produtoAdd.js"></script>
}
在我的控制器上:
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd([Bind("TituloProduto,ImagemProduto,TituloPremio,ImagemPremio")] Produto produto, IFormFile imagemPro, IFormFile imagemPre)
{
if (!ModelState.IsValid)
{
return Json(new { success = false, msg = "1" });
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPro.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemProduto = imagemPro.FileName;
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPre.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemPremio = imagemPre.FileName;
}
_context.Add(produto);
await _context.SaveChangesAsync();
return Json(new { success = true });
}
我的脚本:
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
//alert('false');
}
});
Create = function () {
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.cache = true;
options.async = true;
contentType = "application/json; charset=utf-8",
options.data = $('#frmAdd').serialize();
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
您的负载和您的内容类型不匹配。 jQuery.serialize 将您的表单数据编码为 application/x-www-form-urlencoded
,但您告诉服务器期望内容类型为 application/json
。最简单的解决方案是更改内容类型。
此外,您可能希望使用表单的表单 submit 事件,而不是按钮上的 'click' 事件。这样做的原因是浏览器除了单击按钮之外还会以其他方式提交表单(例如,在文本输入时按“enter”键)。提交将处理所有这些方法。
另一个注意事项:您创建 options
对象的方法可以使用,但该语法有点笨拙。最常见的“最佳实践”是声明与对象内联的属性:
var options = {
type: 'POST',
url: '/api/ProdutoAdd',
// etc ...
success: function (data) {
},
// etc ...
};
这使您不必在每个 属性 之前键入 options.
。
我建议你创建一个viewModel
public class ProdutoViewModel
{
public Produto Produto {get; set;}
public IFormFile ImagemPro {get; set;}
public IFormFile ImagemPre {get; set;}
}
动作(也删除 Bind 属性)
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd(ProdutoViewModel model )
我建议您使用提交按钮而不是 ajax,这对您来说会容易得多
@model ProdutoViewModel
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
....
<input type="submit" value="Criar" class="btn app-btn-primary">
</form>
1.ModelBinding通过name属性绑定属性,你这里的参数名是imagemPro
/imagemPre
.
2.The jQuery serialize()
方法将不包括输入文件元素。因此用户选择的文件不会包含在序列化值中。
您需要创建一个 FormData
对象,将文件附加到该对象,然后将表单字段值也附加到同一个 FormData 对象。您可以简单地遍历所有输入字段并添加它。
这是您可以遵循的完整工作演示:
@model Produto
//add `method="post"` in form tag
//otherwise it will not generate token input
<form class="settings-form" id="frmAdd" enctype="multipart/form-data" method="post">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="@Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="@Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="@Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="@Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
@section scripts{
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/admin/js/produtoAdd.js"></script>
}
JS:
<script>
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
}
});
Create = function () {
var fdata = new FormData();
var fileInput1 = $('#ImagemProduto')[0];
var file1 = fileInput1.files[0];
fdata.append("imagemPro", file1);
var fileInput2 = $('#ImagemPremio')[0];
var file2 = fileInput2.files[0];
fdata.append("imagemPre", file2);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.contentType = false; //change here...
options.processData= false; //add this...
options.data = fdata;
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
</script>
需要通过 AJAX jQuery/JSON.
使用 MVC 模型投标上传文件我之前使用的是正常的提交表单,但现在我需要更改为 AJAX。 我怎样才能做到这一点?我的意思是,使用 MVC 和 AJAX 进行投标,序列化我的表格或类似的东西。
现在,我的控制器上的 imagemPro 和 imagemPre 总是 'null'。
在我看来:
@model Ri.Models.Produto
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="@Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="@Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="@Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="@Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
@section scripts{
<script src="~/admin/js/produtoAdd.js"></script>
}
在我的控制器上:
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd([Bind("TituloProduto,ImagemProduto,TituloPremio,ImagemPremio")] Produto produto, IFormFile imagemPro, IFormFile imagemPre)
{
if (!ModelState.IsValid)
{
return Json(new { success = false, msg = "1" });
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPro.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemProduto = imagemPro.FileName;
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPre.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemPremio = imagemPre.FileName;
}
_context.Add(produto);
await _context.SaveChangesAsync();
return Json(new { success = true });
}
我的脚本:
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
//alert('false');
}
});
Create = function () {
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.cache = true;
options.async = true;
contentType = "application/json; charset=utf-8",
options.data = $('#frmAdd').serialize();
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
您的负载和您的内容类型不匹配。 jQuery.serialize 将您的表单数据编码为 application/x-www-form-urlencoded
,但您告诉服务器期望内容类型为 application/json
。最简单的解决方案是更改内容类型。
此外,您可能希望使用表单的表单 submit 事件,而不是按钮上的 'click' 事件。这样做的原因是浏览器除了单击按钮之外还会以其他方式提交表单(例如,在文本输入时按“enter”键)。提交将处理所有这些方法。
另一个注意事项:您创建 options
对象的方法可以使用,但该语法有点笨拙。最常见的“最佳实践”是声明与对象内联的属性:
var options = {
type: 'POST',
url: '/api/ProdutoAdd',
// etc ...
success: function (data) {
},
// etc ...
};
这使您不必在每个 属性 之前键入 options.
。
我建议你创建一个viewModel
public class ProdutoViewModel
{
public Produto Produto {get; set;}
public IFormFile ImagemPro {get; set;}
public IFormFile ImagemPre {get; set;}
}
动作(也删除 Bind 属性)
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd(ProdutoViewModel model )
我建议您使用提交按钮而不是 ajax,这对您来说会容易得多
@model ProdutoViewModel
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
....
<input type="submit" value="Criar" class="btn app-btn-primary">
</form>
1.ModelBinding通过name属性绑定属性,你这里的参数名是imagemPro
/imagemPre
.
2.The jQuery serialize()
方法将不包括输入文件元素。因此用户选择的文件不会包含在序列化值中。
您需要创建一个 FormData
对象,将文件附加到该对象,然后将表单字段值也附加到同一个 FormData 对象。您可以简单地遍历所有输入字段并添加它。
这是您可以遵循的完整工作演示:
@model Produto
//add `method="post"` in form tag
//otherwise it will not generate token input
<form class="settings-form" id="frmAdd" enctype="multipart/form-data" method="post">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="@Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="@Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="@Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="@Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
@section scripts{
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/admin/js/produtoAdd.js"></script>
}
JS:
<script>
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
}
});
Create = function () {
var fdata = new FormData();
var fileInput1 = $('#ImagemProduto')[0];
var file1 = fileInput1.files[0];
fdata.append("imagemPro", file1);
var fileInput2 = $('#ImagemPremio')[0];
var file2 = fileInput2.files[0];
fdata.append("imagemPre", file2);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.contentType = false; //change here...
options.processData= false; //add this...
options.data = fdata;
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
</script>