24

有没有办法让发布的文件 ( <input type="file" />) 参与 ASP.NET MVC 中的模型绑定,而无需手动查看自定义模型绑定器中的请求上下文,也无需创建仅将发布的文件作为输入的单独操作方法?

我原以为这会起作用:

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) { ... } 

但考虑到上述情况,MyFile它甚至不是绑定上下文中值提供者值的一部分。OtherProperty当然是。)但如果我这样做,它会起作用:

public ActionResult Create(HttpPostedFileBase postedFile, ...) { ... } 

那么,为什么当参数是模型时没有发生绑定,我怎样才能让它工作呢?我对使用自定义模型绑定器没有任何问题,但是如何在自定义模型绑定器中执行此操作而不查看Request.Files["MyFile"]

为了一致性、清晰性和可测试性,我希望我的代码能够自动绑定模型上的所有属性,包括绑定到已发布文件的属性,而无需手动检查请求上下文。我目前正在使用Scott Hanselman 所写的方法测试模型绑定。

还是我以错误的方式解决这个问题?你会如何解决这个问题?或者由于 Request.Form 和 Request.Files 之间的分离历史,这是设计上不可能的?

4

4 回答 4

29

It turns out the reason is that ValueProviderDictionary only looks in Request.Form, RouteData and Request.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:

public ActionResult Create(MyModel myModel, HttpPostedFileBase myModelFile) { }

As long as myModelFile is actually the name of the file input form field, there's no need for any custom stuff.

于 2009-06-08T21:21:55.680 回答
14

Another way is to add a hidden field with the same name as the input:

<input type="hidden" name="MyFile" id="MyFileSubmitPlaceHolder" />

The DefaultModelBinder will then see a field and create the correct binder.

于 2009-10-29T21:39:39.923 回答
7

您是否查看过他从您链接到的帖子(通过另一个...)链接到的帖子?

如果没有,它看起来很简单。这是他使用的模型粘合剂:

public class HttpPostedFileBaseModelBinder : IModelBinder {
    public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
        HttpPostedFileBase theFile =
            bindingContext.HttpContext.Request.Files[bindingContext.ModelName];
        return new ModelBinderResult(theFile);
    }
}

他将其注册Global.asax.cs如下:

ModelBinders.Binders[typeof(HttpPostedFileBase)] = 
    new HttpPostedFileBaseModelBinder();

并以如下形式发布:

<form action="/File/UploadAFile" enctype="multipart/form-data" method="post">
    Choose file: <input type="file" name="theFile" />
    <input type="submit" />
</form>

All the code is copied straight off the blog post...

于 2009-06-06T22:33:20.577 回答
-17

You don't need to register a custom binder, HttpPostedFileBase is registered by default in the framework:

public ActionResult Create(HttpPostedFileBase myFile)
{
    ...
}

It helps to read a book every once in awhile, instead of relying solely on blogs and web forums.

于 2009-06-07T06:34:14.403 回答