Je travaille sur un site Web ASP.NET MVC dont le formulaire permet le téléchargement de fichiers à l'aide de l'option en-type multipart/form data sur la balise de formulaire,
<form enctype="multipart/form-data" method="post" action='<%= Url.Action("Post","Entries",new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}) %>'>
Comment pourrais-je écrire ceci pour faire un post de formulaire ASP.NET MVC Ajax à la place?
Utilisation:
AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})
Mais dans le second cas, je ne suis pas sûr que cela fonctionnera.
C'est possible mais c'est un long chemin .. 1ère étape: écrivez votre formulaire
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" />
}
Étape 2: intercepter la demande et l'envoyer au serveur
<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>
Étape 3: Comme vous effectuez un appel ajax, vous souhaiterez probablement remplacer une image ou un élément de type 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 est une chaîne cryptée en base64. Dans mon cas, c'est la source de l'image.
De cette façon, j'ai réussi à changer une photo de profil et ensuite, la photo est immédiatement mise à jour. Assurez-vous également d’ajouter dans Application_Start (global.asax) ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
Pretty Nice no?
P.S .: Cette solution fonctionne donc n'hésitez pas à demander plus de détails.
Je suis tombé sur ce petit bidouillage qui le résout 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);
Le plugin jquery forms prend en charge le téléchargement de fichiers de cette manière.
Code que j'ai utilisé et ça marche !! C'est une copie de la solution @James 'Fluffy' Burton. Je viens d’improviser sa réponse pour que les nouveaux venus chez MVC soient en mesure de comprendre rapidement les conséquences.
Voici mon point de vue:
@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);
Voici mon contrôleur:
[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 });
}
Voici la note rapide du code ci-dessus: Grâce à Ajax, j’ai posté mon fichier Excel (* .csv) sur le serveur et je l'ai lu sur un DataTable à l'aide d'un paquet Nuget (LumenWorksCsvReader).
Hourra! Ça marche. Merci @James
J'ai effectivement répondu à la question moi-même ...
<% using (Ajax.BeginForm("Post", "Entries", new { id = ViewData.Model.MemberDetermination.DeterminationMemberID }, new AjaxOptions { UpdateTargetId = "dc_goal_placeholder" }, new { enctype = "multipart/form-data" }))
Si vous devez utiliser OnSuccess
AjaxOption et/ou utiliser Request.IsAjaxRequest()
dans le contrôleur pour vérifier le type de demande, par exemple i.e.
@using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "elementToUpdate", OnSuccess = "mySuccessFuntion(returnedData)", OnFailure = "myFailureFuntion(returnedData)"}, new { enctype = "multipart/form-data" }))
Ensuite, vous pouvez utiliser le code suivant (j'ai modifié la réponse de @James 'Fluffy' Burton). Cela convertira également le texte de la réponse en objet JSON s'il le peut (vous pouvez l'omettre si vous le souhaitez).
<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. J'utilise la fonction javascript eval()
pour convertir la chaîne en une fonction ... si quelqu'un a une meilleure solution, merci de commenter . J'utilise aussi JQuery JSON.parse()
donc ce n'est pas une solution javascript Vanilla mais elle n'est pas obligatoire le script doit fonctionner pour pouvoir être supprimé.
Pour ceux qui ont encore des problèmes d'utilisation de @Ajax.BeginForm
pour les enctypes multiparties/les téléchargements de fichiers dans MVC
L'exécution de l'outil «Inspecter l'élément» sur un élément de formulaire généré par l'assistant @Ajax.BeginForm
révèle que celui-ci remplace, de manière plutôt inexplicable, le paramètre de contrôleur spécifié. C'est le cas si vous avez implémenté un contrôleur distinct pour votre publication partielle.
Une solution rapide au problème consiste à spécifier explicitement votre valeur d'attribut d'action HTML en tant que /<yourcontrollername>/<youractionname>
.
@using (Ajax.BeginForm("", "", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "<TargetElementId>", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data", action = "/<Controller>/<Action>" }))
J'ai mélangé la réponse de Brad Larson à Amirhossein Mehrvarzi, car celle-ci ne fournissait aucun moyen de la traiter et qu'Amirhossein causait 2 publications. validation du modèle avant envoi.
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);
Ajax.BegineForm () fonctionne avec des données de formulaire en plusieurs parties et voici l'exemple de code de travail correspondant:
Vue:
@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éthode d'action du contrôleur:
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. Assurez-vous que l'attribut "name" du contrôle de téléchargement de fichier et le nom du paramètre transmis à la méthode Action UploadFile () doivent être identiques (dans ce cas, "fichiers").
De ma petite enquête. Toutes les réponses ci-dessus semblent être correctes en fonction du problème rencontré avec Ajax.BeginForm. Cependant, je viens d’observer que le problème vient de la bibliothèque javascript ~/Scripts/jquery.unobtrusive-ajax.min.js. Donc, dans mon cas, je l'ai simplement retiré du modèle d'affichage et j'ai en quelque sorte décidé d'utiliser le plug-in JQuery Form pour mon besoin requis, ainsi que le formulaire HTML. Cela a été suggéré ci-dessus.