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

发布于 2024-07-22 13:31:56 字数 1175 浏览 2 评论 0 原文

有没有办法让发布的文件()参与 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 之间的分离历史,这在设计上是不可能的吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

祁梦 2024-07-29 13:31:56

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

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

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

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.

甜尕妞 2024-07-29 13:31:56

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

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

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

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.

嘿看小鸭子会跑 2024-07-29 13:31:56

您是否看过他从 这篇文章 链接到的内容/www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx" rel="noreferrer">您链接到的(通过 另一个...)?

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

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>

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

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:

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

He registers it in Global.asax.cs as follows:

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

and posts with a form that looks like this:

<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...

爱*していゐ 2024-07-29 13:31:56

您不需要注册自定义绑定器,HttpPostedFileBase 默认情况下已在框架中注册:

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

它有助于每隔一段时间读一本书,而不是仅仅依赖博客和网络论坛。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文