MVC: Comment poster le téléchargement de fichiers et d'autres champs de formulaire à une action

Je crée une application de bibliothèque de documents avec un DocumentController qui doit télécharger une image miniature de chaque doument dans la bibliothèque. Je veux garder le champ de téléchargement de fichier sur le même formulaire de création/édition que les autres champs (Titre, Description, CategoryId, etc.).
Le problème est que je ne suis pas sûr de pouvoir mélanger ou imbriquer les balises de formulaire pour

Html.BeginForm("Create", "Document", FormMethod.Post, enctype = "multipart/form-data")

Et

Html.BeginForm()

Mon point de vue est le suivant:

 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Publications.WebUI.Models.DocumentEditViewModel >" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <fieldset>
        <legend>Edit
            <%=  Html.Truncate(Model.Document.Title, 50)%></legend>
        <%= Html.ValidationSummary(false) %>
        <% using (Html.BeginForm())
           { %>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Document.Title) %>
        </div>
        <div class="editor-field">
            <%= Html.HiddenFor(model => model.Document.DocumentId ) %>
            <%= Html.ValidationMessageFor(model => model.Document.Title) %>
            <%= Html.TextBoxFor(model => model.Document.Title)%>
        </div>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Document.DocumentUrl)%>
        </div>
        <div class="editor-field">
            <%= Html.ValidationMessageFor(model => model.Document.DocumentUrl)%>
            <%= Html.TextBoxFor(model => model.Document.DocumentUrl)%>
        </div>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Document.Description)%>
        </div>
        <div class="editor-field">
            <%= Html.ValidationMessageFor(model => model.Document.Description)%>
            <%= Html.TextAreaFor(model => model.Document.Description) %>
        </div>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Document.ThumbnailUrl )%>
        </div>
        <div class="editor-field">
            <% using (Html.BeginForm("Create", "Document",
                    FormMethod.Post, new { enctype = "multipart/form-data" }))
               {%>
            <%= Html.ValidationMessageFor(model => model.Document.ThumbnailUrl )%>
            <input name="uploadFile" type="file" />
            <% } %>
        </div>
        <div class="formActions">
            <div class="backNav">
                <%= Html.ActionLink("< Back to List", "Index") %>
            </div>
            <div class="submit">
                <input type="submit" value="Save" />
            </div>
            <% } %>
        </div>
    </fieldset>
</asp:Content>

Mon contrôleur prend juste le modèle de Document et HttpPostedFileBase et tente de télécharger la fichier sur le serveur et enregistrer le Document dans le référentiel

 [HttpPost]
 public ActionResult Create(Document document, HttpPostedFileBase uploadFile)
 {

     if (ModelState.IsValid)
     {
         //Process file upload
         //Update repository

      }

       return View("List");
  }

Je me demande donc s'il est possible de télécharger le fichier et de mettre à jour le référentiel sur la même action et comment dois-je structurer ma vue pour faciliter cela.

33
demandé sur Liam 2011-03-01 03:11:07

1 réponses

J'ai regardé dans le Grand Livre de Steve Sanderson (Pro ASP.NET MVC 2 Framework) et son application Exemple de magasin de sport a un formulaire de téléchargement de fichier où il y a des éléments de formulaire standard mélangés avec un élément de téléchargement de fichier "multipart/form-data". Il semble donc que le type multipart suffise pour tous les éléments de formulaire sur la page. Bien que l'image téléchargée soit enregistrée dans la base de données, je suis sûr que je peux faire un fichier.SaveAs() dans la même Action. Merci, M. Sanderson. J'espère que vous ne me dérange pas de reproduire votre code...

Voir

    <asp:Content ContentPlaceHolderID="MainContent" runat="server">
    <h1>Edit <%= Model.Name %></h1>

    <% using (Html.BeginForm("Edit", "Admin", FormMethod.Post, 
                             new { enctype = "multipart/form-data" })) { %>
        <%= Html.Hidden("ProductID") %>
        <p>
            Name: <%= Html.TextBox("Name") %>
            <div><%= Html.ValidationMessage("Name") %></div>
        </p>
        <p>
            Description: <%= Html.TextArea("Description", null, 4, 20, null) %>
            <div><%= Html.ValidationMessage("Description") %></div>
        </p>
        <p>
            Price: <%= Html.TextBox("Price") %>
            <div><%= Html.ValidationMessage("Price") %></div>
        </p>
<p>
    Category: <%= Html.TextBox("Category") %>
    <div><%= Html.ValidationMessage("Category") %></div>
</p>
<p>
    Image:
    <% if(Model.ImageData == null) { %>
        None
    <% } else { %>
        <img src="<%= Url.Action("GetImage", "Products", 
                                 new { Model.ProductID }) %>" />
    <% } %>
    <div>Upload new image: <input type="file" name="Image" /></div>                
</p>

<input type="submit" value="Save" /> &nbsp;&nbsp;
        <%=Html.ActionLink("Cancel and return to List", "Index") %>
    <% } %>
</asp:Content>

Contrôleur

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Product product, HttpPostedFileBase image)
    {
        if (ModelState.IsValid) {
            if (image != null) {
                product.ImageMimeType = image.ContentType;
                product.ImageData = new byte[image.ContentLength];
                image.InputStream.Read(product.ImageData, 0, image.ContentLength);
            }
            productsRepository.SaveProduct(product);
            TempData["message"] = product.Name + " has been saved.";
            return RedirectToAction("Index");
        }
        else // Validation error, so redisplay same view
            return View(product);
    }
36
répondu Brendan 2011-03-01 21:34:12