3

Been trying to implement a file uploader with multiple files and I keep getting an invalid ModelState. Here's my code (just the essentials)

ViewModel:

public IEnumerable<HttpPostedFileBase> files { get; set; }

view.cshtml:

@model ITManagement.ViewModels.AssetViewModel

@using (Html.BeginForm(new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
    <h4>Asset</h4>
    <hr />
.
. The rest of the form is located here
. 
.
    <div class="form-group">
        @Html.LabelFor(viewModel => viewModel.objectModel.documentInfo.documents.fileContent, htmlAttributes: new {@class = "control-label col-md-2" } )
        <div class="col-md-2">
            <input class="single-line" id=@Html.IdFor(viewModel => viewModel.files)
                   name=@Html.NameFor(viewModel => viewModel.files)
                   type="file" multiple="multiple" />
        </div>
    </div>

controller:

    [Route("create", Name = AssetsControllerRoute.Create)]
    public ActionResult create()
    {
        AssetViewModel evm = new AssetViewModel();
        return View(evm);
    }

    // POST: Assets/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("create")]
    public ActionResult create(AssetViewModel asset)
    {
        if (ModelState.IsValid)
        {
            erepo.add(asset.objectModel);
            return RedirectToAction("Index");
        }

        return View(asset);
    }

I've already encountered this question and then subsequently this error and answer, but I'm still missing something. The files variable is empty when I upload a file and submit the form. I do see using Request.Files in my searching, but what's the difference between trying to bind to an IEnumerable<HttpPostedFileBase> and using Request.Files?

Here's the reason for the invalid ModelState:

"The parameter conversion from type 'System.String' to type 'System.Web.HttpPostedFileBase' failed because no type converter can convert between these types."

Community
  • 1
  • 1
Luminous
  • 1,771
  • 2
  • 24
  • 43

1 Answers1

10

The one piece of code I had wrong was this

@using (Html.BeginForm(new { enctype = "multipart/form-data" }))

This should instead be

@using (Html.BeginForm("create", "assets", FormMethod.Post, new { enctype = "multipart/form-data" }))

"create" represents the controller action, and "assets" represents the controller name. I gave it these 3 parameters and everything was fine.

Luminous
  • 1,771
  • 2
  • 24
  • 43
  • To clarify, the problem was the lack of `enctype`, which is required to post files. The top code snippet attempts to use an overload that simply doesn't exist. The overload that accepts one object sets the route values, not the HMTL attributes. – Sinjai Nov 01 '18 at 15:53
  • @Sinjai I'd argue what you said by saying the `enctype` is being specified in the top code snippet. I was just using the wrong overload for what I needed to happen. – Luminous Nov 01 '18 at 16:57
  • Sure, the word "enctype" is in the first snippet. But you're not actually setting it, hence the error. I just wanted to add a note for any future readers. Otherwise, it could be ambiguous what the core of the issue was -- i.e. did you need to specify the action/controller? The FormMethod? I was brought here by forgetting about `enctype` in my HTML attributes. – Sinjai Nov 01 '18 at 17:10
  • @Sinjai Saying the problem was "the lack of something" typically means (to me at least that) it's missing completely. I see the point you're making though and it's valid. I ultimately was using the incorrect overload usage because I didn't understand MS's documentation or whatever the reason was back then. – Luminous Nov 01 '18 at 17:53
  • Sure, I probably should've said something like "the lack of `enctype` in the rendered HTML". – Sinjai Nov 02 '18 at 03:08