views:

783

answers:

1

I have set the enctype to: multipart/form-data yet whenever I submit this form, the Request.ContentType is: application/x-www-form-urlencoded and the contents of the upload can't be retrieved from Request.Files.

Here is my View:

    <% using (Html.BeginForm("Import", "Content", FormMethod.Post, new { enctype = "multipart/form-data" })) { %>

<p>
    <%= Html.CheckBox("DeleteExisting")%> Delete Existing Records?
</p>   

<p>
    <input type="file" name="FileUpload" id="FileUpload" /> Select a dump file.
</p>

<p>
    <input type="submit" value="Import Now" />
</p>

<% } %>

Here is my Action:

        [HttpPost]
    public ActionResult Import(FormCollection fc)
    {
        string chkDelete = fc["DeleteExisting"];
        //string filename = fc["FileUpload"];

        if (!chkDelete.Equals("false"))
        {
            //TODO: delete existing records, if specified
        }


        var inputFile = Request.Files["FileUpload"];


        return View();
    }

In the PostBack, the "fc" variable is filled and I can access the checkbox's value and can get the filename of the upload.

Why would my enctype be ignored?

I have tried manually putting the form tag in the view with the attributes in different positions, but that made no difference.

The only thing I can think is that this Import form is nested within the MasterPage's form, but that doesn't seem like it should be a problem. Plus I have this form enclosed properly.

Any suggestions?

+2  A: 

I believe there are two issues at play here:

The only thing I can think is that this Import form is nested within the MasterPage's form, but that doesn't seem like it should be a problem. Plus I have this form enclosed properly.

This is probably most of the problem - there are two things that worry me:

  1. Nested forms are not legal (X)HTML - the browser is quite legitimately allowed to ignore the second form declaration, and close the form at the first form tag it comes to - so that could well be the problem you're seeing.
  2. As we're dealing with ASP.NET MVC, there's no reason at all to have one big enclosing form in the master page, that's just going to get in the way (like we're possibly seeing here).

I recommend that you remove the form from the master page and just add them in when you need them around an actual form. That may well solve the problem you're seeing as well.

Secondly, you'll need to add a parameter based on the HttpPostedFileBase to your action:

public ActionResult Import(FormCollection fc, HttpPostedFileWrapper FileUpload)
{
  string chkDelete = fc["DeleteExisting"];

  if (null != FileUpload && 0 < FileUpload.ContentLength) {
   // We have an upload.

   string filename = FileUpload.FileName;

    if (!chkDelete.Equals("false"))
    {
        //TODO: delete existing records, if specified
    }

    // Stream file in from FileUpload.InputStream e.g.:
    var bytesOriginal = new byte[FileUpload.ContentLength];
    FileUpload.InputStream.Read(bytesOriginal, 0, FileUpload.ContentLength);

    //Read from the byte array as you would any normal file.
  }

  return View();
}

I've just tried this in a simple view (no master page, no nested forms) and it behaved exactly as I'd expect - without the HttpPostedFileWrapper the FormCollection only contained the checkbox.

Zhaph - Ben Duguid
You should not need the extra parameter.
Jace Rhea
@jacerhea Hmm, that could have been a hang up from my originally building it in v1, and using a ViewModel that didn't have anywhere to put the uploaded file, and all online references stating I wouldn't be able to get the uploaded file out of a FormCollection...
Zhaph - Ben Duguid
Thanks for the quick reply Ben, but the HttpPostedFileBase parameter didn't help. It was null on post back.
Roger D
It was the nested forms. I rec-created the view without a master page and now get the upload via the parameter as you suggested Ben.
Roger D
@Roger D: I think there's two parts to it - 1) Your nested form is being ignored by your browser - I've seen this behaviour elsewhere as well. 2) Once you've resolved that, you will need the HttpPostedFileBase/HttpPostedFileWrapper parameter - I've just tried your code in an empty view, and only got the checkbox returned in the form collection, but when I added a HttpPostedFileWrapper parameter to the controller, that was populated with the file I'd uploaded.
Zhaph - Ben Duguid