jmak24
jmak24

Reputation: 41

API POST calls to upload a List of objects containing IFormFile

I'm using IFormFile from ASP.NET Core 2.2 to build a file upload web service call. Because I need specific data associated with every file upload, I created a custom model class to contain the data with an IFormFile property.

public class Document
{
    public string FileId { get; set; }
    public string FileTitle { get; set; }
    public string CategoryId { get; set; }

    public IFormFile Content { get; set; }
}

The below works fine when only one Document is being uploaded.

[HttpPost]
[Route("UploadDoc")]
public async Task<IActionResult> DocumentUpload ([FromForm] Document document) { }

However, I wish to accept a list of Documents to be uploaded at once. When I configure my POST to accept a list, it no longer works. I know for a fact that IList<IFormFile> works, but the issue is that I need additional data for each file.

[HttpPost]
[Route("UploadDoc")]
public async Task<IActionResult> DocumentUpload ([FromForm] IList<Document> document) { }

I am testing my API using Postman and I've included a screenshot of my form-data call. When executed, my Postman will hang. Oddly enough, when I remove the IFormFile property from my Document class, the call works. Can I make this work or is there a workaround?

Postman call

Upvotes: 4

Views: 5394

Answers (4)

Wahid Bitar
Wahid Bitar

Reputation: 14094

It's a known bug

As a workaround, you can wrap the IFormFile in another class and it will work

    public class Company
    {
        public IList<Person> Employees { get; set; } = new List<Person>();
    }

    public class Person
    {
        public FormFileWrapper IdImage { get; set; }
    }

    public class FormFileWrapper
    {
        public IFormFile File { get; set; }
    }

then you don have to add the index in your html

<form action="http://localhost:5000/api/Values" method="post" enctype="multipart/form-data">
    <p><input type="file" name="Employees[0].IdImage.File"></p>
    <p><input type="file" name="Employees[1].IdImage.File"></p>
    <p><button type="submit">Submit</button></p>
</form>

Upvotes: 3

L01NL
L01NL

Reputation: 1813

This is actually a bug in ASP.NET Core 2.2, but there is a work-around for it.

Include the Index of the item into your form post, like this:

Html form:

<input type="hidden" name="document.Index" value="0" />
<input type="file" name="document.Content[0]" />

<input type="hidden" name="document.Index" value="1" />
<input type="file" name="document.Content[1]" />

API call:

key                    value
document.Index         0
document.Content[0]    (binary)
document.Index         1
document.Content[1]    (binary)

I have created a reproduction of the bug and included the work-around.

Upvotes: 1

Mahesh Bakali
Mahesh Bakali

Reputation: 34

Why can't you try a concrete implementation of IFormFile. And use that concrete type as list parameter.

public class Document : IFormFile
{
    public string ContentType => throw new NotImplementedException();

    public string ContentDisposition => throw new NotImplementedException();

    public IHeaderDictionary Headers => throw new NotImplementedException();

    public long Length => throw new NotImplementedException();

    public string Name => throw new NotImplementedException();

    public string FileName => throw new NotImplementedException();

    public void CopyTo(Stream target)
    {
        throw new NotImplementedException();
    }

    public Task CopyToAsync(Stream target, CancellationToken cancellationToken = default(CancellationToken))
    {
        throw new NotImplementedException();
    }

    public Stream OpenReadStream()
    {
        throw new NotImplementedException();
    }
}

You can customize your class as well by adding required properties. It's worth trying. Give a try and let me know how do you go.

Upvotes: 0

Edward
Edward

Reputation: 29986

For passing List Object from postman to api, you could try struct like parameterName[index].fieldName.

Here is a demo which works for you.

enter image description here

Upvotes: 0

Related Questions