Is there any way to get posted files (<input type="file" />
) to take part in model binding in ASP.NET MVC without manually looking at the request context in a custom model binder, and without creating a separate action method which only takes a posted file as input?
I would have thought that this would work:
class MyModel {
public HttpPostedFileBase MyFile { get; set; }
public int? OtherProperty { get; set; }
}
<form enctype="multipart/form-data">
<input type="file" name="MyFile" />
<input type="text" name="OtherProperty" />
</form>
public ActionResult Create(MyModel myModel) { ... }
But given the above scenario, MyFile
isn't even part of the value provider values in the binding context. (OtherProperty
is, of course.) But it works if I do this:
public ActionResult Create(HttpPostedFileBase postedFile, ...) { ... }
So, why does no binding occur when the parameter is a model, and how can I make it work? I have no problem with using a custom model binder, but how can I do this in a custom model binder without looking at Request.Files["MyFile"]
?
For consistency, clarity and testability, I'd like my code to provide automatic binding of all properties on a model, including those bound to posted files, without manually inspecting the request context. I am currently testing model binding using the approach Scott Hanselman wrote about.
Or am I going about this in the wrong way? How would you solve this? Or is this not possible by design due to the history of separation between Request.Form and Request.Files?
You don't need to register a custom binder,
HttpPostedFileBase
is registered by default in the framework:It helps to read a book every once in awhile, instead of relying solely on blogs and web forums.
It turns out the reason is that
ValueProviderDictionary
only looks inRequest.Form
,RouteData
andRequest.QueryString
to populate the value provider dictionary in the model binding context. So there's no way for a custom model binder to allow posted files to participate in model binding without inspecting the files collection in the request context directly. This is the closest way I've found to accomplish the same thing:As long as
myModelFile
is actually the name of thefile
input form field, there's no need for any custom stuff.Another way is to add a hidden field with the same name as the input:
The DefaultModelBinder will then see a field and create the correct binder.
Have you looked at this post which he links to from the one you linked to (via another one...)?
If not, it looks quite simple. This is the model binder he uses:
He registers it in
Global.asax.cs
as follows:and posts with a form that looks like this:
All the code is copied straight off the blog post...