当参数是Model时,ASP.NET MVC发布了文件模型绑定

bzl*_*zlm 24 asp.net-mvc defaultmodelbinder modelbinders httppostedfilebase

有没有办法让发布的文件(<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) { ... } 
Run Code Online (Sandbox Code Playgroud)

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

public ActionResult Create(HttpPostedFileBase postedFile, ...) { ... } 
Run Code Online (Sandbox Code Playgroud)

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

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

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

bzl*_*zlm 30

事实证明,原因是ValueProviderDictionary只查看Request.Form,RouteDataRequest.QueryString在模型绑定上下文中填充值提供程序字典.因此,自定义模型绑定器无法允许已发布的文件参与模型绑定,而无需直接检查请求上下文中的文件集合.这是我发现完成同样事情的最接近的方式:

public ActionResult Create(MyModel myModel, HttpPostedFileBase myModelFile) { }
Run Code Online (Sandbox Code Playgroud)

只要myModelFile实际上是file输入表单字段的名称,就不需要任何自定义的东西.

  • *注意:*不要忽略表单上的`enctype`属性.它必须指定为"multipart/form-data"`.否则,在输入标记上匹配名称为`name`属性的`HttpPostedFileBase`参数在POST时将保持为"null". (5认同)

Bri*_*nce 14

另一种方法是添加一个与输入同名的隐藏字段:

<input type="hidden" name="MyFile" id="MyFileSubmitPlaceHolder" />
Run Code Online (Sandbox Code Playgroud)

然后DefaultModelBinder将看到一个字段并创建正确的绑定器.

  • 看起来像ASP.NET MVC 2 RC处理这个没有隐藏字段. (2认同)

Tom*_*han 6

你看过他链接到的那个帖子(通过另一个 ...)吗?

如果没有,它看起来很简单.这是他使用的模型绑定器:

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

他注册Global.asax.cs如下:

ModelBinders.Binders[typeof(HttpPostedFileBase)] = 
    new HttpPostedFileBaseModelBinder();
Run Code Online (Sandbox Code Playgroud)

以及表单如下所示的帖子:

<form action="/File/UploadAFile" enctype="multipart/form-data" method="post">
    Choose file: <input type="file" name="theFile" />
    <input type="submit" />
</form>
Run Code Online (Sandbox Code Playgroud)

所有代码都直接从博客文章中复制出来......