Chris
Chris

Reputation: 45

Upload file and primitive type to Web Api with ajax

I am currently trying to upload an Image file together with a string with ajax to an Asp.Net Core Api with no luck.

I looked at: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects and thought it would be easy to send both an Image file and a string together in a FormData object, but only the Image is received.

In javascript I am appending the data and sending it with an ajax post:

    let formData = new FormData();
    formData.append("code", "123");
    formData.append("userFile", document.querySelector("#imgInput").files[0]);

    $.ajax({
        async: true,
        type: "post",
        data: formData,
        processData: false,
        contentType: false,
        url: "https://localhost:22333/api/postmethod",
        success: function (data, response, jqXHR) {
            console.log(response);
        },
        error: function (jqXHR, response, errorThrown) {

        }
    });

And in Asp.Net Core the method is:

    [HttpPost]
    [Route("postmethod")]
    public async Task PostMethod(IFormFile code, IFormFile userFile)

I have tried setting the code parameter to both IFormFile and string, but nothing happens. The userFile parameter is always set correctly to the Image file, which makes me wonder what I am doing wrong when uploading the code string.

TLDR: Can't upload both a image file and string with ajax call to Asp.Net Core 3.1 Api.

Is there a better way to upload the files and parameter?

Upvotes: 0

Views: 287

Answers (1)

perustaja
perustaja

Reputation: 191

Basically there are 2 problems here. One, you cannot specify more than one parameter. Straight from the WebAPI documentation:

When an action has more than one parameter bound from the request body, an exception is thrown.

However, instead we can just make a complex object here. You will want to do some reading on viewmodels/DTOs if you havent, but to keep things simple we can just use a model here.

Secondly, the reason why the IFormFile would bind but not the string has to do with the inferred data sources in the same documentation. [FromForm] was inferred for IFormFile but not string (nor the Image type here, either). Adding [FromForm] here tells the action to bind from the form data.

    [HttpPost]
    [Route("postmethod")]
    public async Task PostMethod([FromForm]Image image)

An example if you wanted to make a form to submit to this api:
HTML (must specify enctype):

@model .../Image
<form method="post" enctype="multipart/form-data" id="imageForm">
    @Html.Editorfor(m => m.Code)
    @Html.EditorFor(m => m.File)
    <input type="submit" value="submit"/>
</form>

JQuery:

    $("#imageForm").submit(function(e) {
        e.preventDefault();
        $.ajax({
            type: "post",
            data: new FormData(this),
            processData: false,
            contentType: false,
            url: "api/postmethod",
            success: function (data, response, jqXHR) {
                alert("Success.");
            },
            error: function (jqXHR, response, errorThrown) {
                alert("Error.")
            }
        });
    })

This is just assuming you want that form, again remember that this will not work similarly with JSON. You can read more about this question at similar ones here and here:

Upvotes: 1

Related Questions