Reputation: 41
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?
Upvotes: 4
Views: 5394
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
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
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
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.
Upvotes: 0