24

¿Hay alguna forma de que los archivos publicados (<input type="file" />) participen en el enlace de modelo en ASP.NET MVC sin consultar manualmente el contexto de solicitud en un archivador de modelo personalizado y sin crear un método de acción separado que solo toma un archivo publicado como entrada?ASP.NET MVC ha publicado el enlace de modelo de archivo cuando el parámetro es Modelo

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

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

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

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

Para mayor coherencia, claridad y capacidad de prueba, me gustaría que mi código proporcione un enlace automático de todas las propiedades de un modelo, incluidas las vinculadas a los archivos publicados, sin inspeccionar manualmente el contexto de solicitud. Actualmente estoy probando el enlace del modelo usando the approach Scott Hanselman wrote about.

¿O estoy haciendo esto de la manera incorrecta? Como resolverias esto? ¿O esto no es posible por diseño debido al historial de separación entre Request.Form y Request.Files?

Respuesta

29

Resulta que la razón es que sólo se ve en ValueProviderDictionaryRequest.Form, RouteData y Request.QueryString para poblar el diccionario proveedor de valor en el contexto de enlace de modelos. Por lo tanto, no es posible que un archivador de modelo personalizado permita que los archivos publicados participen en el enlace del modelo sin inspeccionar directamente la recopilación de archivos en el contexto de la solicitud.Este es el camino más cercano que he encontrado para lograr la misma cosa:

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

Mientras myModelFile es en realidad el nombre del campo de formulario file de entrada, no hay necesidad de ningún material personalizado.

+5

* Nota: * no pase por alto el atributo 'enctype' en el formulario. Debe especificarse como '" multipart/form-data "'. De lo contrario, el argumento 'HttpPostedFileBase' con el nombre correspondiente como el atributo' name' en la etiqueta de entrada, permanecerá 'null' en POST. –

+0

He usado el mismo pero obtuve el error: - No puedo enlazar varios parámetros, en mi $ .ajax tengo establecido: - tipo: 'POST', dataType: 'json', contentType: 'multipart/form-data' , data: formData – ujjaval

6

¿Ha mirado this post con el que se vincula desde the one you linked to (a través de another one ...)?

Si no, parece bastante simple. Este es el modelo de aglutinante que utiliza:

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

Se registra en Global.asax.cs de la siguiente manera:

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

y postes con una forma 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 el código se copia directamente de la publicación del blog ...

+0

En realidad, este es el enfoque que estoy usando actualmente. Pero hay dos problemas con este enfoque: 1; utiliza el contexto de solicitud (a través de bindingContext.HttpContext.Request), que realmente no quiero, y 2; solo maneja un escenario donde la publicación solo consiste en un archivo cargado (esto, por supuesto, podría cambiarse fácilmente). – bzlm

+0

Además, BindModel (ModelBindingContext bindingContext) se parece al código de prelanzamiento. También hay un ControllerContext allí. – bzlm

+1

¿Has echado un vistazo al código fuente de MVC Framework? No estoy seguro de cómo funcionan los archivadores modelo "normal", pero realmente no veo cómo podría obtener valores de formulario sin utilizar la colección HttpContext.Current.Request.Form [] * en algún lugar * a lo largo de la carretera ... http://weblogs.asp.net/scottgu/archive/2008/03/21/asp-net-mvc-source-code-now-available.aspx –

-16

No es necesario registrar una carpeta de encargo, HttpPostedFileBase se registra de manera predeterminada en el marco:

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

Ayuda a read a book de vez en cuando, en lugar de confiar únicamente en los blogs y foros web.

+0

He editado la pregunta para tener más claro el hecho de que no quiero un método de acción que tome un archivo publicado como su único parámetro. ¿Hay alguna manera de lograr lo mismo si el archivo publicado es solo una de las muchas propiedades en el modelo? (Tengo el otro libro ASP.NET MVC, por cierto. :) – bzlm

+0

Esta es la respuesta correcta; Tuve el mismo problema hace un tiempo. HttpPostedFileBase enlazará pero HttpPostedFile no lo hará. –

+0

No, HttpPostedFileBase no enlazará utilizando el enlace de proveedor de valor estándar en el cuaderno de modelo predeterminado. Sin embargo, se unirá al método en esta respuesta. – bzlm

14

Otra forma es añadir un campo oculto con el mismo nombre que la entrada:

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

El DefaultModelBinder entonces verá un campo y crear la carpeta correcta.

+2

Parece que ASP.NET MVC 2 RC maneja esto sin el campo oculto. –

+0

absolutamente correcto, estoy usando ASP.NET MVC 2 y puedo vincular exitosamente mi entrada de archivo a mi modelo sin hacer ningún trabajo extra de ningún tipo. ¡Fantástico! – Pandincus

Cuestiones relacionadas