24

Existe-t-il un moyen d'obtenir des fichiers publiés (<input type="file" />) pour participer à la liaison de modèle dans ASP.NET MVC sans consulter manuellement le contexte de demande dans un classeur de modèle personnalisé , et sans créer une méthode d'action distincte qui prend seulement un fichier publié en entrée?ASP.NET MVC a publié la liaison de modèle de fichier lorsque le paramètre est Modèle

j'aurais pensé que cela fonctionnerait:

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

Mais étant donné le scénario ci-dessus, MyFile est même pas partie des valeurs du fournisseur de valeur dans le contexte de liaison. (OtherProperty est, bien sûr.) Mais il fonctionne si je fais ceci:

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

Alors, pourquoi ne pas de liaison se produit lorsque le paramètre est un modèle, et comment puis-je le faire fonctionner? Je n'ai aucun problème avec l'utilisation d'un classeur de modèle personnalisé, mais comment puis-je le faire dans un classeur modèle personnalisé sans regarder Request.Files["MyFile"]? Par souci de cohérence, de clarté et de testabilité, je souhaite que mon code fournisse une liaison automatique de toutes les propriétés d'un modèle, y compris celles liées aux fichiers publiés, sans inspecter manuellement le contexte de la demande. Je suis actuellement en train de tester la liaison de modèle en utilisant the approach Scott Hanselman wrote about. Ou est-ce que je vais à ce sujet dans le mauvais sens? Comment résoudriez-vous cela? Ou n'est-ce pas possible par conception en raison de l'historique de séparation entre Request.Form et Request.Files?

Répondre

29

Il se trouve la raison en est que ValueProviderDictionary ne regarde que dans Request.Form, RouteData et Request.QueryString pour remplir le dictionnaire de fournisseur de valeur dans le contexte de liaison de modèle. Il est donc impossible pour un classeur de modèle personnalisé d'autoriser les fichiers publiés à participer à la liaison de modèle sans inspecter directement la collection de fichiers dans le contexte de requête.Ceci est le plus proche comme je l'ai trouvé pour accomplir la même chose:

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

Tant que myModelFile est en fait le nom du champ de formulaire d'entrée file, il n'y a pas besoin d'une substance personnalisée.

+5

* Note: * ne pas négliger l'attribut 'enctype' sur le formulaire. Il doit être spécifié comme "multipart/form-data" '. Sinon, l'argument 'HttpPostedFileBase' avec le nom correspondant comme attribut' name' sur la balise d'entrée, restera 'null' sur POST. –

+0

J'ai utilisé la même chose mais j'ai eu l'erreur: - Impossible de lier plusieurs paramètres, dans mon $ .ajax j'ai défini: - type: 'POST', dataType: 'json', contentType: 'multipart/form-data' , data: formData – ujjaval

6

Avez-vous regardé this post à partir de the one you linked to (via another one ...)?

Sinon, cela semble assez simple. Ceci est le liant modèle qu'il utilise:

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

Il enregistre en Global.asax.cs comme suit:

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

et des postes avec une forme qui ressemble à ceci:

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

Toutes les le code est copié directement à partir de l'article de blog ...

+0

En fait, c'est l'approche que j'utilise actuellement. Mais il y a deux problèmes avec cette approche: 1; il utilise le contexte de la requête (via bindingContext.HttpContext.Request), ce que je ne veux vraiment pas, et 2; il ne gère qu'un scénario où la publication consiste uniquement en un fichier téléchargé (cela pourrait bien sûr être facilement modifié). – bzlm

+0

En outre, BindModel (ModelBindingContext bindingContext) ressemble à un code de pré-version. Il y a aussi un ControllerContext. – bzlm

+1

Avez-vous regardé le code source de MVC Framework? Je ne suis pas sûr de savoir comment les classeurs de modèle "normaux" fonctionnent, mais je ne peux pas vraiment voir comment vous seriez capable de saisir des valeurs de formulaire sans utiliser la collection HttpContext.Current.Request.Form [] * quelque part * le long de la route ... http://weblogs.asp.net/scottgu/archive/2008/03/21/asp-net-mvc-source-code-now-available.aspx –

-16

Vous n'avez pas besoin d'enregistrer un classeur personnalisé, HttpPostedFileBase est enregistré par défaut dans le cadre:

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

Il aide à read a book temps en temps, au lieu de compter uniquement sur les blogs et les forums.

+0

J'ai modifié la question pour être plus clair sur le fait que je ne veux pas d'une méthode d'action qui prend comme seul paramètre un fichier publié. Y a-t-il un moyen d'accomplir la même chose si le fichier publié n'est qu'une des nombreuses propriétés du modèle? (J'ai l'autre livre ASP.NET MVC, au fait. :) – bzlm

+0

C'est la bonne réponse; J'ai eu le même problème il y a un moment. HttpPostedFileBase se liera mais HttpPostedFile ne le fera pas. –

+0

Non, HttpPostedFileBase ne liera pas en utilisant la liaison du fournisseur de valeur standard dans le classeur de modèle par défaut. Il se liera dans la méthode dans cette réponse, cependant. – bzlm

14

Une autre façon est d'ajouter un champ caché avec le même nom que l'entrée:

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

Le DefaultModelBinder verra alors un champ et créer le liant correct.

+2

On dirait que ASP.NET MVC 2 RC gère ceci sans le champ caché. –

+0

absolument correct, j'utilise ASP.NET MVC 2 et je peux lier avec succès mon entrée de fichier à mon modèle sans faire n'importe quel travail supplémentaire. Fantastique! – Pandincus

Questions connexes