tutorial net mvc iformfile form data beginform asp asp.net html asp.net-mvc

iformfile - ¿Cómo hacer una publicación de formulario ASP.NET MVC Ajax con multipart/form-data?



upload file net core 2 (11)

Estoy trabajando en un sitio web ASP.NET MVC que tiene un formulario que permite la carga de archivos usando la opción enctype de datos multipart / form en la etiqueta del formulario como tal

<form enctype="multipart/form-data" method="post" action=''<%= Url.Action("Post","Entries",new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}) %>''>

¿Cómo escribiría esto para hacer una publicación ASP.NET MVC Ajax en su lugar?


  1. Puede utilizar algunos cargadores adicionales (por ejemplo, el cargador de múltiples archivos jQuery ) (prefiero esta opción y prefiero no utilizar MS Ajax)
  2. Utilizar:

    AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})

Pero en el segundo caso, no estoy seguro de que funcione.


Ajax.BegineForm () funciona con datos de formulario multiparte y aquí está el ejemplo de código de trabajo para el mismo:

Ver:

@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" /> }

Método de acción del controlador:

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); } }

PD Asegúrese de que el atributo "nombre" del control de carga del archivo y el nombre del parámetro pasado al método de acción UploadFile () tenga que ser el mismo (es decir, "archivos" en este caso).


Código que utilicé y funciona !! Es una copia de la solución @James ''Fluffy'' Burton. Simplemente estoy improvisando su respuesta para que las personas que son nuevas en MVC puedan comprender rápidamente las consecuencias.

Los siguientes son mi Vista:

@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);

Los siguientes son mi controlador:

[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 }); }

Lo que sigue es la nota rápida del código anterior: A través de Ajax, he publicado mi archivo excel (* .csv) en Server y lo he leído en una DataTable usando un paquete Nuget (LumenWorksCsvReader).

¡Viva! Funciona. Gracias @James


Combiné la respuesta de Brad Larson con Amirhossein Mehrvarzi, porque la respuesta de Brad no estaba proporcionando ninguna forma de manejar la respuesta y Amirhossein estaba causando 2 devoluciones. Acabo de agregar ($ (''# formBacklink''). Valid ()) para llamar a la validación del modelo antes del envío.

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);


De hecho, yo mismo respondí la pregunta ...

<% using (Ajax.BeginForm("Post", "Entries", new { id = ViewData.Model.MemberDetermination.DeterminationMemberID }, new AjaxOptions { UpdateTargetId = "dc_goal_placeholder" }, new { enctype = "multipart/form-data" }))


De mi pequeña investigación. Todas las respuestas anteriores parecen ser correctas dependiendo del problema que se tenga con Ajax.BeginForm. Sin embargo, acabo de observar que el problema es con la biblioteca javascript ~ / Scripts / jquery.unobtrusive-ajax.min.js en algún caso. Entonces, en mi caso, simplemente lo eliminé del modelo de vista y decidí usar el complemento JQuery Form para la necesidad que necesitaba, junto con el Formulario HTML. Esto ha sido sugerido arriba.



Es posible pero es un largo camino. Paso 1: escribe tu formulario

ex:

@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" /> }

Paso 2: interceptar la solicitud y enviarla al servidor

<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>

Paso 3: como haces una llamada ajax probablemente quieras reemplazar alguna imagen o algo de multipart/form-data

ex:

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); } }); }

La variable MSG es una cadena cifrada en base64. En mi caso, es la fuente de la imagen.

De esta forma logré cambiar una imagen de perfil y luego la imagen se actualiza inmediatamente. También asegúrese de agregar en Application_Start (global.asax) ValueProviderFactories.Factories.Add(new JsonValueProviderFactory()); Muy bonito, ¿no?

PD: Esta solución funciona, así que no dude en preguntar más detalles.


Me encontré con este pequeño truco, que lo resuelve muy bien

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);


Si necesita utilizar OnSuccess AjaxOption y / o use Request.IsAjaxRequest() en el controlador para verificar el tipo de solicitud, es decir,

@using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "elementToUpdate", OnSuccess = "mySuccessFuntion(returnedData)", OnFailure = "myFailureFuntion(returnedData)"}, new { enctype = "multipart/form-data" }))

Luego puede usar el siguiente código (he modificado la respuesta de @James ''Fluffy'' Burton). Esto también convertirá el texto de respuesta al objeto JSON si puede (puede omitir esto si lo desea).

<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>

NB: uso la función javascript eval() para convertir la cadena en una función ... si alguien tiene una mejor solución, por favor comente. También uso JQuery JSON.parse() así que esta no es una solución vainilla de JavaScript, pero no es necesaria para que el script funcione, por lo que podría eliminarse.


Para aquellos que todavía tienen problemas al usar @Ajax.BeginForm para @Ajax.BeginForm de múltiples partes / archivos cargados en MVC

Diagnóstico y solución propuesta

La ejecución de la herramienta "Inspeccionar elemento" en un elemento de formulario generado por el @Ajax.BeginForm revela que el asistente, de forma inexplicable, anula el parámetro del controlador especificado. Este es el caso si implementó un controlador separado para su devolución de datos parcial.

Una solución rápida para el problema es especificar explícitamente el valor del atributo de acción html como /<yourcontrollername>/<youractionname> .

Ejemplo

@using (Ajax.BeginForm("", "", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "<TargetElementId>", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data", action = "/<Controller>/<Action>" }))