asp.net-mvc modelbinders defaultmodelbinder httppostedfilebase

ASP.NET MVC publicó el enlace del modelo de archivo cuando el parámetro es Modelo



asp.net-mvc modelbinders (4)

¿Hay alguna forma de obtener archivos publicados ( <input type="file" /> ) para participar en el enlace del modelo en ASP.NET MVC sin mirar manualmente el contexto de la solicitud en un cuaderno de modelos personalizado y sin crear un método de acción separado? que solo toma un archivo publicado como entrada?

Habría pensado que esto funcionaría:

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

Pero dado el escenario anterior, MyFile ni siquiera es parte de los valores del proveedor de valores en el contexto de enlace. ( OtherProperty es, por supuesto). Pero funciona si hago esto:

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

Entonces, ¿por qué no se produce vinculación cuando el parámetro es un modelo y cómo puedo hacer que funcione? No tengo ningún problema con el uso de una carpeta de modelos personalizada, pero ¿cómo puedo hacer esto en una carpeta de modelos personalizada sin mirar los Request.Files["MyFile"] ?

Para mayor coherencia, claridad y comprobabilidad, me gustaría que mi código proporcione el enlace automático de todas las propiedades en un modelo, incluidos aquellos vinculados a archivos publicados, sin inspeccionar manualmente el contexto de la solicitud. Actualmente estoy probando el enlace de modelos utilizando el enfoque sobre el que Scott Hanselman escribió .

¿O voy a hacer esto de manera equivocada? Como resolverias esto? ¿O no es posible por diseño debido al historial de separación entre Request.Form y Request.Files?


¿Has visto esta publicación a la que se vincula desde la que has vinculado (a través de otra ...)?

Si no, parece bastante simple. Este es el modelo de carpeta que usa:

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

Lo registra en Global.asax.cs siguiente manera:

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

y mensajes con un formulario que se parece a esto:

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

Todo el código se copia directamente de la entrada del blog ...


No es necesario registrar un HttpPostedFileBase personalizado, HttpPostedFileBase se registra de forma predeterminada en el marco:

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

Es útil leer un libro de vez en cuando, en lugar de confiar únicamente en blogs y foros web.


Otra forma es agregar un campo oculto con el mismo nombre que la entrada:

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

El DefaultModelBinder verá un campo y creará el archivador correcto.


Resulta que la razón es que ValueProviderDictionary solo busca en Request.Form , RouteData y Request.QueryString para rellenar el diccionario del proveedor de valores en el contexto de enlace del modelo. Por lo tanto, no hay forma de que una carpeta de modelos personalizada permita que los archivos publicados participen en el enlace de modelos sin inspeccionar directamente la colección de archivos en el contexto de la solicitud. Esta es la forma más cercana que he encontrado para lograr lo mismo:

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

Mientras myModelFile sea ​​realmente el nombre del campo de formulario de entrada de file , no hay necesidad de ningún material personalizado.