views:

2345

answers:

4

I am trying to upload a file with ASP.NET MVC.

The following code work perfectly fine:

// Read in the image data.
byte[] binaryData = null;
HttpPostedFileBase uploadedFile = Request.Files["ImageFileName"];
if (uploadedFile != null &&
    uploadedFile.ContentLength > 0)
    {
        binaryData = new byte[uploadedFile.ContentLength];
        uploadedFile.InputStream.Read(binaryData, 
                                      0,
                                      uploadedFile.ContentLength);
    }

But what I am trying to do is use the new FileCollectionModelBinder found in the futures assembly.

I've found these two blog posts here and here explaining what to do. I follow these instructions but havne't had any luck -> the file object is always null.

Here is my method.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "Subject, Content")]
                           Post post, 
                           HttpPostedFileBase file)
{
    UpdateModel(post);
    ...
}

Notice how i'm trying to upload a file AND upload some post information, to a Post object.

Can anyone make any suggestions?

For the record, I have wired up the ModelBinder in my global.asax.cs. I've also made sure the form is a post with the enctype added:-

<form method="post" enctype="multipart/form-data" action="/post/create">
A: 

For the past week i have been building an upload/file manager system for my MVC project and my original attempt was to post additional post data with the multipart files values. this proved too difficult for my time constraints. my approach now is to create the "respective record" to which files/images may be 'attached' (as it is in my case), -then- upload ('attach') the files/images after the record is present.

for example: 1) create event record, 2) attach images with upload control

My action that receives the multipart post uses the concepts from Hanselman's post.

I cant say i've tried the built-in complex-type binding for files (HttpPostedFileBase) but i'd suggest that it would be more complex than my present solution given that from reading the post Hanselman wrote above - i've learned that the files collection returned in the Request is only a loosely typed collection.

I'd suggest sticking to your original code and trying to make that more safe for your purposes.

cottsak
+4  A: 

No bloody way :(

I figured out that answer and it's pretty lame.

I had to have the argument NAME being identical to the Id/Name values of the input type="file" element!!! (not sure if it's either or both element values ... i didn't check that bit out).

so this is the answer.

Html input element. (note the value of the Id/Name)

<input type="file" id="imageFileName" name="imageFileName" class="upload" />

Controller method

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "Subject, Content")]Post post,
    HttpPostedFileBase imageFileName)
{
...
}

shees!

Pure.Krome
Does your view contain other HTML elements that relate to your Post model? I have a model with a ImagePath property along with others. In the view there is all the HTML elements for my model along with a <input type="file" id="imagePath" name="imagePath" /> for that property. Do you just put the strongly typed model in the Controller along with the HttpPostedFileBase and you'll have access to the uploaded file and I can set the ImageFilePath then? Not sure you can set the model on a post action?
Jon
What's lame about this? How else would ASP.NET MVC be able to bind a posted file to a certain parameter in your action method?
bzlm
lame because it requires BOTH attributes to have the same value. Why not just take the ID (which is usually a unique value).. ??
Pure.Krome
+2  A: 

Remember you also need to open your form like this:

<form enctype="multipart/form-data" ...
joshcomley
Yep - sure do .. and i had that.
Pure.Krome
+1  A: 

Not sure if this is relevant to the question, but I've just found a way to get model binding for HttpPostedFileBase working, within complex objects. Unfortunately I had to make a change to the ASP.NET MVC source code, so it isn't for everybody.

In System.Web.Mvc.ValueProviderDictionary.PopulateDictionary(), the value provider is being populated with the contents of Request.Form, Request.QueryString, and RouteData - but NOT Request.Files. Add the following lines to "fix" this (I say "fix" because there may be a reason the ASP.NET MVC team didn't do it in the first place).

HttpFileCollectionBase files = ControllerContext.HttpContext.Request.Files;
if (files != null)
{
    string[] keys = files.AllKeys;
    foreach (string key in keys)
    {
        HttpPostedFileBase file = files[key];
        ValueProviderResult result = new ValueProviderResult(file, file.FileName, currentCulture);
        AddToDictionaryIfNotPresent(key, result);
    }
}
Tim Jones
ooo. that is interesting. would love to hear some thoughts from the MVC team ... Phil? Eilon? Anyone?
Pure.Krome