Subida de ficheros utilizando HTML5 y Ajax

Recientemente, tuve la obligación de implementar una carga de ficheros utilizando sólo JavaScript y Ajax Post, sin necesidad de utilizar el objeto RequestContext o los objetos FormData. El requisito era enviar el archivo subido por el usuario a un método WebAPI. El archivo enviado no debe obtenerse utilizando Request.Files y tampoco debe enviarse utilizando el objeto FormData de JavaScript. Después de varios intentos probando diferentes códigos, se me ocurrió la solución. La puedes ver a continuación.

En primer lugar vamos a ver la parte cliente. La página HTML solo contiene un control para la subida de archivos y un botón.

<input type="file" id="files" name="file" />
<button id="uploadbtn">Upload</button>
 

Definimos el evento click del botón de subida usando jQuery:

$(document).ready(function () {
          $("#uploadbtn").click(readBlob);
      });

Definimos las funciones ReadBLOB y getB64Str como a continuación:

function readBlob() {
          var files = document.getElementById('files').files;
          if (!files.length) {
              alert('Please select a file!');
              return;
          }

          var file = files[0];
          var blob = file.slice();

          var filetype = file.type;
          var filename = file.name;

          var reader = new FileReader();

          reader.onloadend = function (evt) {
              if (evt.target.readyState == FileReader.DONE) { // DONE == 2

                  var cont = evt.target.result
                  var base64String = getB64Str(cont);

                  var model = {
                      contentType: filetype,
                      contentAsBase64String: base64String,
                      fileName: filename
                  };

                  $.ajax({
                      url: '/api/File/ProcFile',
                      type: 'POST',
                      data: JSON.stringify(model),
                      processData: false,
                      async: false,
                      contentType: 'application/json',
                      complete: function (data) {
                          console.log(data.responseText);
                      },
                      error: function (response) {
                          console.log(response.responseText);
                      }
                  });
              }
          };

          reader.readAsArrayBuffer(blob);
}

function getB64Str(buffer) {
          var binary = '';
          var bytes = new Uint8Array(buffer);
          var len = bytes.byteLength;
          for (var i = 0; i < len; i++) {
              binary += String.fromCharCode(bytes[i]);
          }
          return window.btoa(binary);
}

Hay muchas maneras de convertir ArrayBuffer a una cadena base64. Una de ellas es utilizar el código de a continuación. Debería ser algo similar a:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(cont)));

El .readAsBinaryString está obsoleto en la actualidad y no se puede utilizar.

El modelo es un simple objeto tal que así:

public class FileModel
{
    public string contentType { get; set; }

    public string contentAsBase64String { get; set; }

    public string fileName { get; set; }

}

El método WebAPI procesa los datos publicados y genera, en el lado del servidor, los archivos de la cadena de base 64 y los guarda en el servidor.

[HttpPost]
public HttpResponseMessage ProcFile(FileModel filemodel)
{
    if (filemodel == null)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }
    else
    {
        var filecontent = filemodel.contentAsBase64String;
        var filetype = filemodel.contentType;
        var filename = filemodel.fileName;

        var bytes = Convert.FromBase64String(filecontent);
        var savedFile = @"c:/temp/copy_of_" + filename;

        using (var file = new FileStream(savedFile, FileMode.Create))
        {
            file.Write(bytes, 0, bytes.Length);
            file.Flush();
        }

        return Request.CreateResponse(HttpStatusCode.OK, savedFile);
    }
}

El código anterior funciona para archivos de hasta 10 MB por lo que pude probar usando Chrome. Para archivos de gran tamaño, Chrome deja de responder. Estoy buscando maneras más eficientes para convertir ArrayBuffer a una cadena base64.

Y este ha sido el artículo en el que trataba explicaros cómo crear una subida de ficheros utilizando HTML5 y Ajax, esperamos que te haya gustado y sepas aplicarlo en tus futuros proyectos. Ya sabes que si nos quieres proponer un tema que quieres ver reflejado como un tutorial o como una práctica, solo tienes que hacer uso del área de comentarios de un poco más abajo. Por el contrario, si quieres enviarnos tus propios tutoriales, puedes hacerlo a través de la intranet de usuarios que está habilitada para ello, a través del menú Enviar Tutorial. Ya sabes, ayúdanos a crecer con tus conocimientos. ¡Un saludo y feliz código!

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP