0

Using Asp.Net.Core 2.2, Visual Studio 2019

I'd like to get the form data and the files in the same controller action. I've can get the files but not the form data or I can get the form data but not the files. How can I get both?

The return value is some Json that I use to pop up a message and to update the page using Jquery/Javascript.

I thought I had done this in but I can't find any examples in my own code libraries. I've been searching on here and the web and there don't seem to be any examples, which leads me to think (a) its trivial and I'm doing something stupid or (b) its not possible

What am I missing?

My Form

<form asp-controller="Admin" asp-action="EditProduct" id="frmItem" method="post" name="frmItem" novalidate="novalidate" enctype="multipart/form-data">
...

My Ajax

$("#uploadFile,#saveUpload").on("click", function (e) {
    e.preventDefault();

    var myForm = $("#frmItem");
    var sUrl = myForm.attr("action");

    var input = document.getElementById("inputGroupFile02");
    var files = input.files;
    var formData = new FormData();

    for (var i = 0; i != files.length; i++) {
        formData.append("importFile", files[i]);
    }

    formData.append("item", myForm.serialize());

    $.ajax({
        type: "POST",
        url: sUrl,
        contentType: false,
        processData: false,
        data: formData,
        success: function (result) {
            showNotify(result.message);
            hide_modal();
        },
        error: function (err) {
            showNotify("There was an error importing. " + err.statusText + " (" + err.status + ")", "warning", "fa fa-exclamation-triangle");
            hide_modal()
        }
    });
});

My Controller

    [HttpPost]
    //[ValidateAntiForgeryToken]
    public async Task<JsonResult> EditItem(Items item, List<IFormFile> importFile, int id)

If I place a break point in the controller and inspect, I can see files (importFile) or I can see data (item) but not both, depending on what method I use

djack109
  • 1,261
  • 1
  • 23
  • 42
  • Files can only be uploaded via `multiform/form-data`, you are sending json-payload. See [this answer](https://stackoverflow.com/a/1342533/455493) for a rough explaination. Its older, but still valid, since part of HTTP Standard. You are merely serializing the form data as json. Not going to work. Also MVC generally only uses `multipart/form-data` where as WebAPI accepts json (or xml) as body content payload. Just stay with MVC approach, its working fine, no need to javascriptify everything – Tseng Jan 04 '20 at 12:59
  • I don't understand what you mean. I just want to post form fields and files using jscript rather than using the standard form method as I don't want to repost the page, i've updated my js code above which brings back form fields in a querystring like format – djack109 Jan 04 '20 at 19:54

2 Answers2

0

change

public async Task<JsonResult> EditItem(Items item, List<IFormFile> importFile, int id)

to

public async Task<JsonResult> EditItem(Items item, [FromBody]List<IFormFile> importFile, int id)

i hope to work.

0

Ok here's what I did

First I changed this

formData.append("item", myForm.serialize());

to this

formData.append("item", JSON.stringify(myForm.serializeArray()));

Then in my controller, I did this

string data = Request.Form["item"];

Items item = new Items();

SystemFunctions.CopyObjects(data, item);

SystemFunctions.CopyObjects is a function I use pretty much everywhere convert or copy objects cleanly from one to the other, in this case, I've overloaded it to take a JSON array string of name/value pairs.

The first thing it does is this

List<JsonToObject> jsonArray = JsonConvert.DeserializeObject<List<JsonToObject>>(CopyFrom);

Which gets an array of these

public partial class JsonToObject
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("value")]
    public string Value { get; set; }
}

And then cycles through that array using the property names stored in the ID element

There is probably a cleaner more elegant way to do this, and I'm more than happy to take suggestions.

I've been through all my code archive and can't find where I've done this before. I've always used poke/post (the old fashioned way). I can't find any way to post a form through Javascript and get the form data and the form files in one hit. I'm consistently getting 400/415 HTML errors

To keep my UI consistent and improve the UX I use JScript posts everywhere and the only thing I return is a JSON response the only time I use poke/post if for page transitions. Any work done on a page keeps you on that page and updates dynamically. And I don't have to worry about double posts or page refreshes

djack109
  • 1,261
  • 1
  • 23
  • 42