Upload multiple files with parameters in ASP.NET Core
Your approach with using _UploadForm
generates the following html (let's focus on input
's only since this is the most important part)
<input class="form-control" name="Title" />
<input class="form-control" name="Description" />
<input type="file" name="File" />
...
<input class="form-control" name="Title" />
<input class="form-control" name="Description" />
<input type="file" name="File" />
... and so on
So name
attributes contains only FileInfo
model's properties names without indexes and this is only suitable for the case when your controller expects single model
public IActionResult Upload(FileInfo vm)
And in order to make your html work with your current controller with list of models
public IActionResult Upload(List<FileInfo> vm)
It should look like this
<!-- version 1 -->
<input class="form-control" name="[0].Title" />
<input class="form-control" name="[0].Description" />
<input type="file" name="[0].File" />
...
<input class="form-control" name="[1].Title" />
<input class="form-control" name="[1].Description" />
<input type="file" name="[1].File" />
... and so on
Or
<!-- version 2 -->
<!-- the name before index must match parameter name in controller -->
<input class="form-control" name="vm[0].Title" />
<input class="form-control" name="vm[0].Description" />
<input type="file" name="vm[0].File" />
...
<input class="form-control" name="[1].Title" />
<input class="form-control" name="[1].Description" />
<input type="file" name="vm[1].File" />
... and so on
This is possible to accomplish using tag helpers and partial view in slightly different way. All you need to do is turn partial view's model to list and update asp-for
expressions.
_UploadForm.cshtml
@model List<SessionStateTest.Models.FileInfo>
@for (int i = 0; i < Model.Count; i++)
{
<div class="form-group">
<label>Title</label>
<input class="form-control" asp-for="@Model[i].Title" />
</div>
<div class="form-group">
<label>Description</label>
<input class="form-control" asp-for="@Model[i].Description" />
</div>
<div class="form-group">
<label></label>
<input type="file" asp-for="@Model[i].File" />
</div>
}
View
<form asp-action="Upload" asp-controller="Home" method="Post" enctype="multipart/form-data">
@await Html.PartialAsync("_UploadForm", Model.Upload)
<div class="col-xs-12">
<input type="submit" value="Upload" class="btn btn-sm btn-info" />
</div>
</form>
It will generate html like in version 1.
Niroda
Updated on June 05, 2022Comments
-
Niroda almost 2 years
My view model:
public class FileInfo { [Required] [StringLength(50, ErrorMessage = "TitleErrorMessage", MinimumLength = 2)] public string Title { get; set; } [Required] [StringLength(100, ErrorMessage = "DesErrorMessage", MinimumLength = 3)] public string Description { get; set; } [Required] [DataType(DataType.Upload)] public IFormFile File { get; set; } }
The following is _UploadForm partial view file:
@model SessionStateTest.Models.FileInfo <div class="form-group"> <label>Title</label> <input class="form-control" asp-for="Title" /> </div> <div class="form-group"> <label>Description</label> <input class="form-control" asp-for="Description" /> </div> <div class="form-group"> <label></label> <input type="file" asp-for="File" /> </div>
That is used in another View with this code:
<form asp-action="AddUploadForm" asp-controller="Home" method="Post"> <input type="submit" value="Add another file" class="btn btn-sm btn-primary" /> </form> <form asp-action="Upload" asp-controller="Home" method="Post" enctype="multipart/form-data"> @foreach (var item in Model.Upload) { @(await Html.PartialAsync("_UploadForm", item)) } <div class="col-xs-12"> <input type="submit" value="Upload" class="btn btn-sm btn-info" /> </div> </form>
Basically
AddUploadForm
action adds a new view model of typeFileInfo
toModel.Upload
which is my main view model. The problem is that the listList<FileInfo> vm
inUpload
action below is totally empty:[HttpPost] [ValidateAntiForgeryToken] public IActionResult Upload(List<FileInfo> vm) { .... some other logic return View(); }
I don't want to use
multiple
attribute because I would like to force user to provide a title and description for every file.Any help is kindly appreciated!
-
Niroda about 5 yearsThank you! that solved the problem. But may I ask why it didn't work when I tried
name="Title[]"
? As far as I know this should work or did I miss something? -
Alexander about 5 years@Niroda I believe this works for PHP but not for ASP.NET :)