Как сделать сообщение формы ASP.NET MVC Ajax с данными multipart/form?
Я работаю над веб-сайтом ASP.NET MVC, который имеет форму, которая позволяет загружать файлы, используя параметр multipate/form data enctype в теге формы, например
<form enctype="multipart/form-data" method="post" action='<%= Url.Action("Post","Entries",new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}) %>'>
Как я могу написать это, чтобы вместо сообщения формы ASP.NET MVC Ajax?
Ответы
Ответ 1
- Вы можете использовать некоторые дополнительные загрузчики (например, jQuery для загрузки нескольких файлов) (я предпочитаю этот путь, и я предпочитаю не использовать MS Ajax)
-
Применение:
AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})
Но во втором случае я не уверен, что он сработает.
Ответ 2
Это возможно, но это долгий путь.
Шаг 1: напишите свою форму
Пример:
@using (Ajax.BeginForm(YourMethod, YourController, new { id= Model.Id }, new AjaxOptions {//needed options }, new { enctype = "multipart/form-data" }))
{
<input type="file" id="image" name="image" />
<input type="submit" value="Modify" />
}
Шаг 2: перехватите запрос и отправьте его на сервер
<script type="text/javascript">
$(function() {
$("#form0").submit(function(event) {
var dataString;
event.preventDefault();
var action = $("#form0").attr("action");
if ($("#form0").attr("enctype") == "multipart/form-data") {
//this only works in some browsers.
//purpose? to submit files over ajax. because screw iframes.
//also, we need to call .get(0) on the jQuery element to turn it into a regular DOM element so that FormData can use it.
dataString = new FormData($("#form0").get(0));
contentType = false;
processData = false;
} else {
// regular form, do your own thing if you need it
}
$.ajax({
type: "POST",
url: action,
data: dataString,
dataType: "json", //change to your own, else read my note above on enabling the JsonValueProviderFactory in MVC
contentType: contentType,
processData: processData,
success: function(data) {
//BTW, data is one of the worst names you can make for a variable
//handleSuccessFunctionHERE(data);
},
error: function(jqXHR, textStatus, errorThrown) {
//do your own thing
alert("fail");
}
});
}); //end .submit()
});
</script>
Шаг 3: Поскольку вы делаете вызов ajax, вы, вероятно, захотите заменить какое-либо изображение или что-то вроде multipart/form-data
Пример:
handleSuccessFunctionHERE(data)
{
$.ajax({
type: "GET",
url: "/Profile/GetImageModified",
data: {},
dataType: "text",
success: function (MSG) {
$("#imageUploaded").attr("src", "data:image/gif;base64,"+msg);
},
error: function (msg) {
alert(msg);
}
});
}
MSG-переменная - это зашифрованная строка base64. В моем случае это источник изображения.
Таким образом мне удалось изменить изображение профиля, после чего изображение сразу обновится.
Также убедитесь, что вы добавили Application_Start (global.asax)
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
Довольно приятно нет?
P.S.: Это Решение работает, поэтому не стесняйтесь спрашивать более подробную информацию.
Ответ 3
Я наткнулся на этот маленький взлом, который прекрасно его разрешает
window.addEventListener("submit", function (e) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = xhr.responseText;
}
}
}
};
xhr.send(new FormData(form));
}
}
}, true);
Ответ 4
Плагин jquery forms поддерживает загрузку файлов в этом путь.
Ответ 5
Код, который я использовал, и он работает! Это копия решения @James 'Fluffy' Burton. Я просто импровизирую его ответ, чтобы люди, которые новичок в MVC, смогут быстро понять последствия.
Ниже представлен мой вид:
@using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "AjaxUpdatePanel" }, new { enctype = "multipart/form-data", id = "frmUploader" })){
<div id="AjaxUpdatePanel">
<div class="form-group">
<input type="file" id="dataFile" name="upload" />
</div>
<div class="form-group">
<input type="submit" value="Upload" class="btn btn-default" id="btnUpload"/>
</div>
</div>}
<script>
window.addEventListener("submit", function (e) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = xhr.responseText;
}
}
}
};
xhr.send(new FormData(form));
}
}
}, true);
Ниже приведен мой контроллер:
[HttpPost]
public JsonResult FileUploader(HttpPostedFileBase upload)
{
if (ModelState.IsValid)
{
if (upload != null && upload.ContentLength > 0)
{
if (upload.FileName.EndsWith(".csv"))
{
Stream stream = upload.InputStream;
DataTable csvTable = new DataTable();
using (CsvReader csvReader = new CsvReader(new StreamReader(stream), true))
{
csvTable.Load(csvReader);
}
}
else
{
return Json(new { dataerror = true, errormsg = "This file format is not supported" });
}
}
else
{
return Json(new { dataerror = true, errormsg = "Please Upload Your file" });
}
}
return Json(new { result = true });
}
Ниже приведена краткая заметка вышеприведенного кода:
Через Ajax я разместил файл excel (*.csv) на сервере и прочитал его в DataTable с помощью пакета Nuget (LumenWorksCsvReader).
Ура! Оно работает. Спасибо @James
Ответ 6
Я сам сам ответил на вопрос...
<% using (Ajax.BeginForm("Post", "Entries", new { id = ViewData.Model.MemberDetermination.DeterminationMemberID }, new AjaxOptions { UpdateTargetId = "dc_goal_placeholder" }, new { enctype = "multipart/form-data" }))
Ответ 7
Для тех, у кого все еще есть проблемы с использованием @Ajax.BeginForm
для многопользовательских enctypes/загрузки файлов в MVC
Диагностика и предлагаемое решение
Запуск инструмента "Осмотреть элемент" в элементе формы, сгенерированном помощником @Ajax.BeginForm
, показывает, что помощник, довольно необъяснимо, переопределяет указанный параметр контроллера. Это тот случай, если вы внедрили отдельный контроллер для частичной обратной передачи.
Быстрое исправление проблемы заключается в том, чтобы явно указать значение атрибута действия html как /<yourcontrollername>/<youractionname>
.
Пример
@using (Ajax.BeginForm("", "", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "<TargetElementId>", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data", action = "/<Controller>/<Action>" }))
Ответ 8
Ajax.BegineForm() работает с данными мультифайловой формы, и здесь пример рабочего кода для него:
Вид:
@using(Ajax.BeginForm("UploadFile","MyPOC",
new AjaxOptions {
HttpMethod = "POST"
},
new
{
enctype = "multipart/form-data"
}))
{
<input type="file" name="files" id="fileUploaderControl" />
<input type="submit" value="Upload" id="btnFileUpload" />
}
Метод действия контроллера:
public void UploadFile(IEnumerable<HttpPostedFileBase> files)
{
HttpPostedFileBase file = files.FirstOrDefault(); //Attach a debugger here and check whether you are getting your file on server side or null.
if (file != null && file.ContentLength > 0)
{
//Do other validations before saving the file
//Save File
file.SaveAs(path);
}
}
P.S. Убедитесь, что атрибут "name" элемента управления загрузчиком файла и имя параметра, переданного методу UploadFile(), должны быть одинаковыми (например, "файлы" в этом случае).
Ответ 9
Я смешал Брэда Ларсона с Амирхосейном Мехрварзи, потому что ответ Брэда не предоставлял никакого способа справиться с ответом, и Амирхосейн вызывал 2 обратной передачи.
Я просто добавил ($ ('# formBacklink'). Valid()), чтобы вызвать проверку модели перед отправкой.
window.addEventListener("submit", function (e) {
if ($('#formBacklink').valid()) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var dataString;
event.preventDefault();
var action = $("#formBacklink").attr("action");
if ($("#formBacklink").attr("enctype") == "multipart/form-data") {
//this only works in some browsers.
//purpose? to submit files over ajax. because screw iframes.
//also, we need to call .get(0) on the jQuery element to turn it into a regular DOM element so that FormData can use it.
dataString = new FormData($("#formBacklink").get(0));
contentType = false;
processData = false;
} else {
// regular form, do your own thing if you need it
}
$.ajax({
type: "POST",
url: action,
data: dataString,
dataType: "json", //change to your own, else read my note above on enabling the JsonValueProviderFactory in MVC
contentType: contentType,
processData: processData,
success: function (data) {
//BTW, data is one of the worst names you can make for a variable
//handleSuccessFunctionHERE(data);
},
error: function (jqXHR, textStatus, errorThrown) {
//do your own thing
}
});
}
}
}
}, true);
Ответ 10
Если вам нужно использовать OnSuccess
AjaxOption и/или использовать Request.IsAjaxRequest()
в контроллере, чтобы проверить тип запроса i.e.
@using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "elementToUpdate", OnSuccess = "mySuccessFuntion(returnedData)", OnFailure = "myFailureFuntion(returnedData)"}, new { enctype = "multipart/form-data" }))
Затем вы можете использовать следующий код (я изменил ответ @James 'Fluffy' Burton). Это также преобразует текст ответа в объект JSON, если он может (вы можете опустить это, если хотите).
<script>
if(typeof window.FormData === 'undefined') {
alert("This browser doesn't support HTML5 file uploads!");
}
window.addEventListener("submit", function (e) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.setRequestHeader("x-Requested-With", "XMLHttpRequest"); // this allows 'Request.IsAjaxRequest()' to work in the controller code
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
var returnedData; //this variable needs to be named the same as the parameter in the function call specified for the AjaxOptions.OnSuccess
try {
returnedData = JSON.parse(xhr.responseText); //I also want my returned data to be parsed if it is a JSON object
}catch(e){
returnedData = xhr.responseText;
}
if (form.dataset.ajaxSuccess) {
eval(form.dataset.ajaxSuccess); //converts function text to real function and executes (not very safe though)
}
else if (form.dataset.ajaxFailure) {
eval(form.dataset.ajaxFailure);
}
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = data;
}
}
}
};
xhr.send(new FormData(form));
}
}
}, true);
</script>
N.B. Я использую функцию javascript eval()
для преобразования строки в функцию... если у кого-то есть лучшее решение, прокомментируйте.
Я также использую JQuery JSON.parse()
, поэтому это не решение ванильного javascript, но для функции script не требуется, чтобы его можно было удалить.
Ответ 11
Из моего небольшого расследования. Все приведенные выше ответы кажутся правильными в зависимости от проблемы, имеющейся у Ajax.BeginForm. Тем не менее, я просто заметил, что проблема связана с библиотекой javascript ~/Scripts/jquery.unobtrusive-ajax.min.js в некотором случае. Поэтому в моем случае я просто удалил его из модели представления и решил использовать плагин JQuery Form для моей необходимой необходимости вместе с HTML-формой. Это было предложено выше.