2009-06-09 24 views
56

Tengo un formulario simple en una aplicación MVC que he hecho. Contiene un campo de archivo para que los usuarios puedan subir una imagen. Todo funciona genialCómo mantener el tipo de entrada = valor de campo de archivo después de la validación fallida en ASP.NET MVC?

El problema es que, si el envío del formulario falla la validación, el contenido del campo del archivo se pierde (otros campos permanecen llenos, ¡htmlHelpers!). ¿Cómo mantengo el campo de archivo poblado después de una validación fallida?

TIA!

Respuesta

53

Los navegadores están diseñados de esta manera debido a los riesgos de seguridad. Es imposible establecer el valor del cuadro de entrada de archivo en fuente HTML o por Javascript. De lo contrario, las secuencias de comandos maliciosas podrían robar algunos archivos privados sin la atención del usuario.

Hay an interesting information sobre el tema.

+0

yup, entiendo el principio de seguridad. Solo desearía que fuera posible para el escenario que describí, simplemente porque la experiencia del usuario me impactó. ;/ – Chaddeus

+8

Para solucionar su problema de UX, el usuario debería volver a seleccionar el archivo: Puede almacenar el archivo en un caché temporal en el servidor cuando el formulario con un archivo configurado se envía por primera vez. Luego, si la validación falla, usted simplemente muestra el nombre de archivo (o miniatura) para indicar que el campo está configurado. Una vez que la validación es exitosa, usted obtiene los datos del archivo de su caché. – tsauerwein

+5

@tsauerwen, bien eso derrota el propósito del modelo de MVCs sin estado. – Triynko

2

Por lo que sé, no puede establecer el valor de un cuadro de entrada de archivo HTML. Sugiero acoplar el cuadro de entrada de archivo con una etiqueta o cuadro de texto.

Luego puede llenarlo con el valor del cuadro de entrada de archivo para volver a enviarlo más tarde.

+0

Interesante ... ¿sabes de un sitio que ha implementado de esta manera? Buscando ejemplos ... gracias. – Chaddeus

+0

Gmail usa algo similar con sus archivos adjuntos. Una vez que el archivo se carga, se convierte en texto. Sin embargo, esto se hace de forma asincrónica con AJAX. – Michael

1

Hay cargadores de archivos basados ​​en flash. Prueba uno de ellos. Algunos de ellos incluso vuelven al cuadro de entrada de archivo normal si el flash y el script java no son compatibles. Aconsejo buscar plugins jQuery.

1

Si el archivo no es demasiado grande, puede basar64 y usarlo como valor para un campo oculto.

0

No puede establecer el valor de un cuadro de entrada de archivo HTML. Como solución alternativa, reemplace el cuadro de carga de archivos con un campo de entrada oculto al generar el formulario después de la validación.

En el envío, rellena el campo oculto con el valor del cuadro de entrada del archivo (para volver a enviarlo más tarde). Recuerde que debe tener ya sea la carga del archivo o nombre de campo oculto presente en un momento dado (no ambos):

Nota: El código siguiente es para ilustración/explicación propósitos solamente. Reemplácelo con el código apropiado para el idioma que usa.

<?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

"Recuerde tener la carga del archivo o el nombre del campo oculto presente en cualquier momento (no ambos)". Bueno, ¿y si, después de la validación, el usuario cambia de opinión y quiere seleccionar un archivo diferente? – Triynko

0

Yo recomendaría hacer la validación de antemano a través de ajax y hacer una actualización parcial de la página. En este caso, no perderá el archivo.

0

No estoy de acuerdo con que se marque "imposible" como respuesta correcta. En caso de que alguien todavía esté buscando una posibilidad, aquí está el trabajo que funcionó para mí. Estoy usando MVC5. La idea es usar una variable de sesión. Obtuve la idea de ASP.Net Form.

(sólo las propiedades relevantes) Mi modelo/modelo de vista:

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

     public HttpPostedFileBase uploadFile { get; set; } 
    } 

En mi controlador (HttpPost): // Salida

[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... 
} 

Por último dentro de mi vista de edición: aquí, estoy condicionalmente mostrando el control de carga de archivos.

< 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> 
 
}

Cuestiones relacionadas