2009-06-09 10 views
56

Ho un modulo semplice in un'app MVC che ho creato. Contiene un campo file in modo che gli utenti possano caricare un'immagine. Funziona tutto alla grande.Come mantenere il tipo di input = valore del campo del file dopo la convalida non riuscita in ASP.NET MVC?

Il problema è che se il modulo di invio non riesce la convalida il contenuto del campo del file viene perso (altri campi rimangono popolati, grazie a HtmlHelpers!). Come mantenere il campo del file popolato dopo una convalida non riuscita?

TIA!

risposta

53

I browser sono progettati in questo modo a causa dei rischi per la sicurezza. È impossibile impostare il valore della casella di input del file nel codice sorgente HTML o JavaScript. Altrimenti lo script dannoso potrebbe rubare alcuni file privati ​​senza l'attenzione dell'utente.

C'è lo an interesting information sull'argomento.

+0

sì, ho capito il principio di sicurezza. Spero solo che sia stato possibile per lo scenario che ho descritto, semplicemente perché ho avuto l'esperienza dell'utente che ne ha risentito. ;/ – Chaddeus

+8

Per risolvere il problema UX che l'utente deve selezionare nuovamente il file: È possibile memorizzare il file in una cache temporanea sul lato server quando il modulo con un file impostato viene inviato per la prima volta. Quindi se la convalida fallisce, è sufficiente mostrare il nome del file (o la miniatura) per indicare che il campo è impostato. Una volta che la convalida ha avuto successo, recuperi i dati del file dalla tua cache. – tsauerwein

+5

@tsauerwen, beh che sconfigge lo scopo del modello stateless di MVCs. – Triynko

2

Per quanto ne so non è possibile impostare il valore di una casella di input del file HTML. Suggerirei di accoppiare la casella di input del file con un'etichetta o una casella di testo.

Quindi è possibile popolare il valore con il valore dalla casella di immissione file da ripresentare in seguito.

+0

Interessante ... sai di un sito che ha implementato in questo modo? Alla ricerca di esempi ... grazie. – Chaddeus

+0

Gmail utilizza qualcosa di simile con i suoi allegati. Una volta caricato, il file diventa testo. Tuttavia questo viene fatto in modo asincrono usando AJAX. – Michael

1

Ci sono caricatori di file basati su flash. Prova uno di loro. Alcuni di essi ritornano alla normale casella di input se lo script flash e java non sono supportati. Ti consiglio di cercare i plugin jQuery.

1

Se il file non è troppo grande, è possibile basarlo64 e utilizzarlo come valore per un campo nascosto.

0

Non è possibile impostare il valore di una casella di input del file HTML. Per ovviare al problema, sostituire la casella di caricamento del file con un campo di input nascosto durante l'output del modulo dopo la convalida.

Al momento dell'invio, si popola il campo nascosto con il valore dalla casella di immissione del file (da ripresentare successivamente). Ricorda di avere sia il caricamento del file o il nome del campo nascosto presente in qualsiasi momento (non entrambi):

Nota: Il codice qui sotto è per illustrazione/spiegazione solo scopi. Sostituiscilo con il codice appropriato alla lingua che usi.

<?php /* You may need to sanitize the value of $_POST['file_upload']; 
* this is just a start */ 
if(isset($_POST['file_upload']) && !empty($_POST['file_upload'])){ ?> 
<input type="hidden" name="file_upload" value="<?php print($_POST['file_upload']); ?>" /> 
<?php } else { ?> 
<input type="file" name="file_upload" /> 
<?php } ?> 
+0

"Ricorda di avere il caricamento del file o il nome del campo nascosto presente in qualsiasi momento (non entrambi)." Bene, cosa succede se, dopo la convalida, l'utente cambia idea e vuole selezionare un file diverso? – Triynko

0

Si consiglia di eseguire la convalida in anticipo tramite ajax e di eseguire un aggiornamento parziale della pagina. In questo caso, non perderai il file.

0

Non sono d'accordo con "impossibile" essere contrassegnato come risposta corretta. Nel caso qualcuno sia ancora alla ricerca di una possibilità, ecco il lavoro che ha funzionato per me. Sto usando MVC5. L'idea è di usare una variabile di sessione. Ho avuto l'idea da ASP.Net Form.

mio modello/ViewModel (solo le proprietà rilevanti):

public partial class emp_leaves 
    { 
     public string fileNameOrig { get; set; } 
     public byte[] fileContent { get; set; } 

     public HttpPostedFileBase uploadFile { get; set; } 
    } 

Nel mio controller (HttpPost): // Verifica

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Edit(emp_leaves emp_leaves) 
{ 
    if (emp_leaves.uploadFile != null && emp_leaves.uploadFile.ContentLength>0 && !string.IsNullOrEmpty(emp_leaves.uploadFile.FileName)) 
    { 
     emp_leaves.fileNameOrig = Path.GetFileName(emp_leaves.uploadFile.FileName); 
     emp_leaves.fileContent = new byte[emp_leaves.uploadFile.ContentLength]; 
     emp_leaves.uploadFile.InputStream.Read(emp_leaves.fileContent, 0, emp_leaves.uploadFile.ContentLength); 
     Session["emp_leaves.uploadFile"] = emp_leaves.uploadFile; //saving the file in session variable here 
    } 
    else if (Session["emp_leaves.uploadFile"] != null) 
    {//if re-submitting after a failed validation you will reach here. 
     emp_leaves.uploadFile = (HttpPostedFileBase)Session["emp_leaves.uploadFile"]; 
     if (emp_leaves.uploadFile != null && emp_leaves.uploadFile.ContentLength>0 && !string.IsNullOrEmpty(emp_leaves.uploadFile.FileName)) 
     { 
      emp_leaves.fileNameOrig = Path.GetFileName(emp_leaves.uploadFile.FileName); 
      emp_leaves.uploadFile.InputStream.Position = 0; 
      emp_leaves.fileContent = new byte[emp_leaves.uploadFile.ContentLength]; 
      emp_leaves.uploadFile.InputStream.Read(emp_leaves.fileContent, 0, emp_leaves.uploadFile.ContentLength);  
     } 
    } 
//code to save follows here... 
} 

Infine nel mio vista edit: qui, sono condizionalmente mostrando il controllo del caricamento del file.

< script type = "text/javascript" > 
 
    $("#removefile").on("click", function(e) { 
 
    if (!confirm('Delete File?')) { 
 
     e.preventDefault(); 
 
     return false; 
 
    } 
 
    $('#fileNameOrig').val(''); 
 
    //toggle visibility for concerned div 
 
    $('#downloadlrfdiv').hide(); 
 
    $('#uploadlrfdiv').show(); 
 
    return false; 
 
    }); < 
 
/script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> 
 
@model PPMSWEB.Models.emp_leaves @{ HttpPostedFileBase uploadFileSession = Session["emp_leaves.uploadFile"] == null ? null : (HttpPostedFileBase)Session["emp_leaves.uploadFile"]; } @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" 
 
})) { @Html.AntiForgeryToken() 
 
<div class="row"> 
 
    @*irrelevant content removed*@ 
 
    <div id="downloadlrfdiv" @((!String.IsNullOrEmpty(Model.fileNameOrig) && (Model.uploadFile==n ull || uploadFileSession !=null)) ? "" : "style=display:none;")> 
 
    <label>Attachment</label> 
 
    <span> 
 
      <strong> 
 
       <a id="downloadlrf" href="@(uploadFileSession != null? "" : Url.Action("DownloadLRF", "emp_leaves", new { empLeaveId = Model.ID }))" class="text-primary ui-button-text-icon-primary" title="Download attached file"> 
 
        @Model.fileNameOrig 
 
       </a> 
 
      </strong> 
 
      @if (isEditable && !Model.readonlyMode) 
 
      { 
 
       @Html.Raw("&nbsp"); 
 
       <a id="removefile" class="btn text-danger lead"> 
 
        <strong title="Delete File" class="glyphicon glyphicon-minus-sign"> </strong> 
 
       </a> 
 
      } 
 
      </span> 
 
    </div> 
 
    <div id="uploadlrfdiv" @(!(!String.IsNullOrEmpty(Model.fileNameOrig) && Model.uploadFile==n ull) && !Model.readonlyMode ? "" : "style=display:none;")> 
 
    <label>Upload File</label> @Html.TextBoxFor(model => model.uploadFile, new { @type = "file", @class = "btn btn-default", @title = "Upload file (max 300 KB)" }) @Html.ValidationMessageFor(x => x.uploadFile) 
 
    </div> 
 
</div> 
 
}

Problemi correlati