Здравствуйте, я могу получить все данные, но я не могу получить ProductIds, это дает мне значение null в параметре запроса функций обработки. SelectedIds не равен нулю, я могу без проблем получить его в своем действии. Я надеюсь, что кто-то может помочь.
Обновлено:
После некоторой отладки я вижу, что мое действие запускается дважды из-за cshtml. Как вы можете видеть в
<form class = "form card-pretify" id = "remaxForm" action = "@Url.Action("EmployeeSessionPost","Product")" method = "post" enctype = "multipart/form-data">
Я использую действие как EmployeeSessionPost. Из-за этого мое действие срабатывает дважды. Обычно раньше это было EmployeeSession. Но я вижу, что не могу получить InstructorId и CsvFile с контроллера.
При использовании EmployeeSessionPost в качестве параметра действия в этой строке он срабатывает дважды, в первом триггере он дает мне selectedIds, но не CsvFile и InstructorId. Во втором триггере он дает мне CsvFile и InstructorId, но не selectedIds.
Если я изменю параметр Url.Action с EmployeeSessionPost на EmployeeSession, он даст мне тот же результат, что и первый триггер.
РЕДАКТИРОВАТЬ2:
Я удалил действие формы и изменил тип кнопки на «кнопку». вот изменения, которые я сделал из комментариев. Это предотвращает двойной триггер, но я не могу получить CsvFile и InstructorId, я просто получаю selectedIds, подобные этому. Как я упоминал ранее
<!--begin::Container-->
<div class = "container-fluid">
<form class = "form card-pretify" id = "remaxForm" method = "post" enctype = "multipart/form-data">
<!--end::Licence-->
<div class = "card-footer">
<button type = "button" class = "btn btn-primary ml-3" id = "btnUpdate">Update</button>
</div>
У меня все тот же блок сценария
[Authorize]
[HttpPost]
public async Task<IActionResult> EmployeeSessionPost(List<int> selectedIds)
{
var csvFile = Request.Form.Files["CsvFile"];
var instructorId = Convert.ToInt32(Request.Form["InstructorId"]);
if (csvFile != null && csvFile.Length > 0)
{
using var stream = new MemoryStream();
await csvFile.CopyToAsync(stream);
await MediatrSend(new Services.Product.Queries.SetEmployeeSessionQuery
{
ProductIds = selectedIds,
InstructorId = instructorId,
CsvFile = csvFile,
});
}
ModelState.AddModelError("CsvFile", "Please select a valid CSV file.");
//return RedirectToAction("ParticipantList", "Product", new { culture = RouteData.Values["culture"].ToString(), selectedIds = selectedIds });
return RedirectToAction("EmployeeSession", "Product", new { culture = RouteData.Values["culture"].ToString() });
}
Мой файл запроса
public class SetEmployeeSessionQuery : IRequest<int>
{
public List<int> ProductIds { get; set; }
public int ProductId { get; set; }
public int ProductEmployeeId { get; set; }
public int InstructorId { get; set; }
public ClaimModel ClaimModel { get; set; }
public IFormFile CsvFile { get; set; }
}
public class SetEmployeeSessionQueryHandler : IRequestHandler<SetEmployeeSessionQuery, int>
{
private readonly IProductEmployeeSessionRepository _productEmployeeSessionRepository;
private readonly IProductEmployeeRepository _productEmployeeRepository;
public SetEmployeeSessionQueryHandler(IProductEmployeeSessionRepository productEmployeeSessionRepository, IProductEmployeeRepository productEmployeeRepository)
{
_productEmployeeSessionRepository = productEmployeeSessionRepository;
_productEmployeeRepository = productEmployeeRepository;
}
public async Task<int> Handle(SetEmployeeSessionQuery request, CancellationToken cancellationToken)
{
.
..
...
.... goes on
вот мой cshtml
@model Remax.Services.DTOs.EmployeeSessionDTO;
@{
ViewData["Title"] = "EmployeeSession";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class = "content d-flex flex-column flex-column-fluid" id = "kt_content">
<!--begin::Entry-->
<div class = "d-flex flex-column-fluid">
<!--begin::Container-->
<div class = "container-fluid">
<form class = "form card-pretify" id = "remaxForm" action = "@Url.Action("EmployeeSession","Product")" method = "post" enctype = "multipart/form-data">
<!--begin::Licence-->
<div class = "card card-custom" data-card = "true" data-card-tooltips = "false">
<div class = "card-header">
<div class = "card-header-inner" data-card-tool = "toggle">
<div class = "card-title">
<h3 class = "card-label">@Html.Raw(Localizer["Form"])</h3>
</div>
<div class = "card-toolbar">
<a href = "#" class = "btn btn-icon btn-sm btn-primary mr-1" data-toggle = "tooltip" data-placement = "top" title = "@Localizer["OpenClose"]">
<i class = "ki ki-arrow-down icon-nm"></i>
</a>
</div>
</div>
</div>
<div class = "card-body">
<div class = "form-group row">
<div class = "col-lg-4">
<label>@Html.Raw(Localizer["Instructor"]) *:</label>
<select class = "form-control kt-selectpicker mr-1" data-actions-box = "true" data-live-search = "true" id = "InstructorId" name = "InstructorId">
<option value = "">@Html.Raw(Localizer["Select"])</option>
@foreach (var o in Model.Instructors)
{
<option value = "@(o.InstructorId)">@Html.Raw(o.NameSurname)</option>
}
</select>
</div>
<div class = "col-lg-4">
<label>@Html.Raw(Localizer["ZoomFile"]) *:</label>
<div class = "custom-file">
<input type = "file" class = "custom-file-input" id = "CsvFile" name = "CsvFile" accept = ".csv">
<label class = "custom-file-label">@Html.Raw(Localizer["ZoomFile"])</label>
</div>
</div>
</div>
</div>
</div>
<!--begin::Card-->
<div class = "card card-custom">
<div class = "card-header flex-wrap border-0 pt-6 pb-0">
<div class = "card-title">
<h3 class = "card-label">
@Html.Raw(Localizer["Products"])
</h3>
</div>
<div class = "card-toolbar">
<!--begin::Button-->
<a href = "javascript:;" class = "btn btn btn-light-primary mr-2 f-filter-btn">
<i class = "la la-filter"></i>@Html.Raw(Localizer["Filter"])
</a>
<!--end::Button-->
</div>
</div>
<div class = "card-body">
<!--begin::Search Form-->
<div class = "mb-7 f-filter-container" id = "searchForm">
<div class = "row align-items-center">
<div class = "col-lg-12">
<div class = "row align-items-center mt-1">
<div class = "col-md-4 form-group">
<label class = "mr-3 mb-0 d-none d-md-block">@Html.Raw(Localizer["StartDate"]):</label>
<div class = "input-group-prepend">
<select data-filter = "1" class = "form-control kt-selectpicker" data-actions-box = "true" data-live-search = "true" data-selected-text-format = "count>1" id = "Month" name = "Month">
<option value = "">@Html.Raw(Localizer["Select"])</option>
@for (byte i = 1; i < 13; i++)
{
<option value = "@i">@(i.ToString().PadLeft(2, '0')) - @Html.Raw(Localizer[String.Format("Month{0}", i)])</option>
}
</select>
<input type = "number" id = "Year" name = "Year" placeholder = "@(Html.Raw(Localizer["Year"]))" class = "form-control ml-1" data-filter = "1" />
</div>
</div>
<div class = "col-md-4 form-group">
<label class = "mr-3 mb-0 d-none d-md-block">@Html.Raw(Localizer["Category"]):</label>
<select data-filter = "1" class = "form-control kt-selectpicker" multiple = "multiple" data-actions-box = "true" data-live-search = "true" data-selected-text-format = "count>1" id = "ProductCategory" name = "ProductCategory">
@for (byte i = 1; i <= 3; i++)
{
<option selected value = "@i">@Html.Raw(Localizer[String.Format("ProductType{0}", i)])</option>
}
</select>
</div>
<div class = "col-md-4 form-group">
<label class = "mr-3 mb-0 d-none d-md-block">@Html.Raw(Localizer["ProductName"]):</label>
<input type = "text" class = "form-control" id = "ProductName" name = "ProductName" placeholder = "@Html.Raw(Localizer["ProductName"])" data-filter = "1" />
</div>
</div>
<div class = "row justify-content-end mt-3">
<div class = "col-md-4 form-group text-right">
<label class = "mr-3 mb-0 d-none d-md-block"> </label>
<a href = "javascript:;" class = "btn btn-danger px-6 font-weight-bold" id = "ktSearch">
<i class = "fa fa-search icon-nm"></i>
<span>@Html.Raw(Localizer["Search"])</span>
</a>
</div>
</div>
</div>
</div>
</div>
<!--end::Search Form-->
<!--begin: Datatable-->
<div class = "datatable datatable-bordered datatable-head-custom" id = "kt_datatable" data-url = "@Url.Action("EmployeeSessionList","Product",new { culture=Model.Language})"></div>
<!--end: Datatable-->
</div>
</div>
<!--end::Card-->
<!--end::Licence-->
<div class = "card-footer">
<button class = "btn btn-primary ml-3" id = "btnUpdate" name = "btnUpdate">@Html.Raw(Localizer["Update"])</button>
</div>
</form>
</div>
<!--end::Container-->
</div>
<!--begin::Entry-->
</div>
<script src = "https://code.jquery.com/jquery-3.6.0.min.js"></script>
@section scripts{
<script src = "~/assets/js/pages/crud/ktdatatable/base/KtDatatable.js?v=@(AppSettings.Version)"></script>
<script src = "~/assets/js/pages/crud/ktdatatable/base/KtDatatable_tr.js?v=@(AppSettings.Version)"></script>
<script src = "~/assets/js/pages/crud/ktdatatable/base/KtDatatable_@(Model.Language.Substring(0,2)).js?v=@(AppSettings.Version)"></script>
<script src = "~/assets/js/pages/forms/product/productlist.js?v=@(AppSettings.Version)"></script>
<script src = "~/assets/js/pages/crud/ktdatatable/base/KtDatatable.min.js?v=@(AppSettings.Version)"></script>
<script src = "~/assets/js/pages/crud/ktdatatable/base/KtDatatable_@(Model.Language.Substring(0,2)).min.js?v=@(AppSettings.Version)"></script>
<script>
var remaxTableScroll = true;
$.checkboxSingleClick = function () { };
var selectedIds = [];
var datatableCols = [
{
selector: true,
field: 'Id',
title: '@Html.Raw(Localizer["Code"])',
width: 35,
},
{
field: 'ProductName',
title: '@Html.Raw(Localizer["Product"])',
width: 235,
},
{
field: 'CategoryName',
title: '@Html.Raw(Localizer["Category"])',
width: 150,
},
{
field: 'StartDateStr',
title: '@Html.Raw(Localizer["StartDate"])',
sortable: 'desc',
width: 90,
},
];
$(document).ready(function () {
datatable.on('datatable-on-check',
function (e, args) {
$.each(args, function (i, a) {
if (selectedIds.indexOf(a) == -1)
selectedIds.push(a);
})
if (selectedIds.length > 0)
$('#setMultiple').show();
console.info(selectedIds);
});
datatable.on('datatable-on-uncheck',
function (e, args) {
$.each(args, function (i, a) {
selectedIds.pop(a);
})
if (selectedIds.length == 0)
$('#setMultiple').hide();
console.info(selectedIds);
});
$('#btnUpdate').on('click', function () {
$.ajax({
type: "POST",
dataType: 'json',
cache: false,
url: '@Url.Action("EmployeeSessionPost", "Product")',
cache: false,
data: {
selectedIds: selectedIds
},
success: function (data) {
}, async: true,
});
});
});
</script>
}
Вот немного информации о типе кнопки: html.com/attributes/button-type
Я понимаю, это выглядит хорошим использованием. Но если я удалю функцию кнопки jquery, я не смогу получить свои selectedIds. Это просто для получения selectedIds. Если я удалю этот блок кода, я смогу легко получить данные CsvFile и InstructorId, но не selectedIds. Я надеюсь, что вы также можете дать мне предложение по этому поводу
Затем удалите действие формы и измените тип кнопки на «кнопку». Поэтому, когда вы нажимаете «Обновить», только jQuery будет отправлять форму.
У меня все тот же ответ после того, как я это сделал, можете ли вы проверить РЕДАКТИРОВАТЬ 2
Если это EDIT не реализовано правильно, можете ли вы изменить код cshtml и опубликовать его как ответ, пожалуйста? Мне лучше понять свою ошибку.
Кажется, вы решили проблему двойной публикации. Для csv/structorId это связано с вашим javascript. Упростите свой js до самого базового уровня, чтобы воспроизвести проблему. Вот как вы учитесь программировать.
Спасибо за ваши комментарии, я исправил проблему и поделился решением в разделе ответов. Вы можете проверить это отсюда





Спасибо за все комментарии, вот мое решение. Вместо того, чтобы публиковать отдельно (как форму, так и ajax), я хотел собрать все данные в форме и получить данные из одного и того же FormData через ajax. Вот измененный код
контроллер/действие
[Authorize]
[HttpPost]
public async Task<IActionResult> EmployeeSessionPost()
{
var csvFile = Request.Form.Files.GetFile("CsvFile");
var instructorId = int.Parse(Request.Form["InstructorId"]);
var selectedIds = Request.Form["SelectedIds"].ToString().Split(',').Select(int.Parse).ToList();
if (csvFile != null && csvFile.Length > 0)
{
using var stream = new MemoryStream();
await csvFile.CopyToAsync(stream);
await MediatrSend(new Services.Product.Queries.SetEmployeeSessionQuery
{
ProductIds = selectedIds,
InstructorId = instructorId,
CsvFile = csvFile,
});
}
ModelState.AddModelError("CsvFile", "Please select a valid CSV file.");
//return RedirectToAction("ParticipantList", "Product", new { culture = RouteData.Values["culture"].ToString(), selectedIds = selectedIds });
return RedirectToAction("EmployeeSession", "Product", new { culture = RouteData.Values["culture"].ToString()});
}
cshtml
<form class = "form card-pretify" id = "remaxForm" action = "@Url.Action("EmployeeSessionPost","Product")" method = "post" enctype = "multipart/form-data">
<div class = "card-footer">
<button type = "button" class = "btn btn-primary ml-3" id = "btnUpdate" name = "btnUpdate">@Html.Raw(Localizer["Update"])</button>
</div>
<script>
var remaxTableScroll = true;
$.checkboxSingleClick = function () { };
var selectedIds = [];
var formdata = new FormData();
$(document).ready(function () {
datatable.on('datatable-on-check',
function (e, args) {
$.each(args, function (i, a) {
if (selectedIds.indexOf(a) == -1)
selectedIds.push(a);
})
if (selectedIds.length > 0)
$('#setMultiple').show();
console.info(selectedIds);
});
datatable.on('datatable-on-uncheck',
function (e, args) {
$.each(args, function (i, a) {
selectedIds.splice(selectedIds.indexOf(a), 1);
})
if (selectedIds.length == 0)
$('#setMultiple').hide();
console.info(selectedIds);
});
$('#btnUpdate').on('click', function () {
var csvFile = $('#CsvFile').prop('files')[0];
var instructorId = $('#InstructorId').val();
formdata.append('CsvFile', csvFile);
formdata.append('InstructorId', instructorId);
formdata.append('SelectedIds', selectedIds)
$.ajax({
type: "POST",
dataType: 'json',
cache: false,
url: '@Url.Action("EmployeeSessionPost", "Product")',
data: formdata,
processData: false,
contentType: false,
success: function (data) {
console.info(data);
},
error: function (xhr, status, error) {
console.info(xhr.responseText);
}
});
});
});
</script>
Если у вас есть лучшее решение, чтобы исправить это, или какие-либо советы по улучшению этой реализации, пожалуйста, поделитесь со мной в комментариях.
Вы отправляете форму с помощью jQuery, а также используете действие отправки формы. Вот почему вы видите две отправки. Измените свою кнопку на
<button type=button" class = "btn btn-primary ml-3" id = "btnUpdate"....ИЛИ удалите обработчик события jQuery onClick. Постарайтесь сделать свой код настолько простым, насколько это возможно. Если бы это был я, я бы удалил код jQuery и сохранил действие отправки формы.