24

Esiste un modo per ottenere i file registrati (<input type="file" />) per partecipare al binding del modello in ASP.NET MVC senza esaminare manualmente il contesto della richiesta in un raccoglitore modello personalizzato e senza creare un metodo di azione separato che richiede solo un file inviato come input?ASP.NET MVC ha pubblicato il binding del modello di file quando il parametro è Modello

avrei pensato che questo dovrebbe funzionare:

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

Ma data la situazione di cui sopra, MyFile non è nemmeno parte dei valori del provider valore nel contesto vincolante. (OtherProperty è, ovviamente.) Ma funziona se faccio questo:

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

Quindi, perché non si fa vincolante verifica quando il parametro è un modello, e come posso farlo funzionare? Non ho alcun problema con l'utilizzo di un raccoglitore modello personalizzato, ma come posso farlo in un raccoglitore modello personalizzato senza guardare a Request.Files["MyFile"]?

Per coerenza, chiarezza e testabilità, mi piacerebbe che il mio codice fornisse il binding automatico di tutte le proprietà su un modello, comprese quelle legate ai file pubblicati, senza ispezionare manualmente il contesto della richiesta. Attualmente sto testando il binding del modello usando the approach Scott Hanselman wrote about.

Oppure sto andando su questo nel modo sbagliato? Come risolverebbe questo? O questo non è possibile in base alla progettazione a causa della cronologia della separazione tra Request.Form e Request.Files?

risposta

29

si scopre il motivo è che ValueProviderDictionary guarda solo in Request.Form, RouteData e Request.QueryString per popolare il dizionario fornitore di valore nel contesto di legame modello. Pertanto, non esiste un modo per un raccoglitore modello personalizzato che consenta ai file registrati di partecipare al bind del modello senza ispezionare direttamente la raccolta di file nel contesto della richiesta.Questo è il modo più vicino che ho trovato per ottenere la stessa cosa:

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

Finché myModelFile è in realtà il nome del campo modulo file di ingresso, non c'è bisogno di alcuna roba personalizzato.

+5

* Nota: * non trascurare l'attributo 'enctype' nel modulo. Deve essere specificato come '" multipart/form-data "'. Altrimenti, l'argomento 'HttpPostedFileBase' con il nome corrispondente come attributo' name' sul tag di input, rimarrà 'null' su POST. –

+0

Ho usato lo stesso, ma ho ottenuto l'errore: - Impossibile associare più parametri, nel mio $ .ajax ho impostato: - tipo: 'POST', dataType: 'json', contentType: 'multipart/form-data' , dati: formData – ujjaval

6

Hai guardato a this post a cui si collega da the one you linked to (via another one ...)?

In caso contrario, sembra piuttosto semplice. Questo è il modello legante che usa:

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

Si registra in Global.asax.cs come segue:

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

e post con una forma che assomiglia a questo:

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

Tutto il il codice viene copiato direttamente dal post del blog ...

+0

In realtà, questo è l'approccio che sto attualmente utilizzando. Ma ci sono due problemi con questo approccio: 1; usa il contesto della richiesta (tramite bindingContext.HttpContext.Request), che in realtà non voglio, e 2; gestisce solo uno scenario in cui il post è costituito solo da un file caricato (ovviamente questo potrebbe essere facilmente modificato). – bzlm

+0

Inoltre, BindModel (ModelBindingContext bindingContext) ha l'aspetto di un codice di pre-rilascio. C'è anche un ControllerContext. – bzlm

+1

Hai dato un'occhiata al codice sorgente di MVC Framework? Non sono sicuro di come funzionano i legatori modello "normale", ma non riesco davvero a vedere come potresti ottenere i valori dei moduli senza utilizzare la raccolta HttpContext.Current.Request.Form [] * da qualche parte * lungo la strada ... http://weblogs.asp.net/scottgu/archive/2008/03/21/asp-net-mvc-source-code-now-available.aspx –

-16

Non è necessario registrare un raccoglitore personalizzato, HttpPostedFileBase è inserito di default nel quadro:

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

aiuta a read a book una volta ogni tanto, invece di basarsi esclusivamente su blog e forum web.

+0

Ho modificato la domanda per essere più chiaro sul fatto che non voglio un metodo di azione che consideri un file inviato come unico parametro. C'è un modo per ottenere lo stesso se il file postato è solo una delle molte proprietà sul modello? (A proposito, ho l'altro libro ASP.NET MVC :) – bzlm

+0

Questa è la risposta corretta; Ho avuto lo stesso problema un po 'di tempo fa. HttpPostedFileBase si collegherà ma HttpPostedFile no. –

+0

No, HttpPostedFileBase non esegue il bind utilizzando il bind del provider del valore standard nel raccoglitore modello predefinito. Si legherà nel metodo in questa risposta, però. – bzlm

14

Un altro modo è quello di aggiungere un campo nascosto con lo stesso nome come input:

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

Il DefaultModelBinder vedrà, quindi, un campo e creare il legante corretta.

+2

Sembra che ASP.NET MVC 2 RC gestisca ciò senza il campo nascosto. –

+0

assolutamente corretto, sto usando ASP.NET MVC 2 e posso legare con successo il mio input di file al mio modello senza fare alcun lavoro extra di sorta. Fantastico! – Pandincus

Problemi correlati