Upload de arquivos em ASP.net sem usar o controle de servidor FileUpload


99

Como posso obter um formulário da web ASP.net (v3.5) para postar um arquivo usando um simples e antigo <input type="file" />?

Não estou interessado em usar o controle de servidor FileUpload do ASP.net.

Respostas:


133

Em seu aspx:

<form id="form1" runat="server" enctype="multipart/form-data">
 <input type="file" id="myFile" name="myFile" />
 <asp:Button runat="server" ID="btnUpload" OnClick="btnUploadClick" Text="Upload" />
</form>

No código por trás de:

protected void btnUploadClick(object sender, EventArgs e)
{
    HttpPostedFile file = Request.Files["myFile"];

    //check file was submitted
    if (file != null && file.ContentLength > 0)
    {
        string fname = Path.GetFileName(file.FileName);
        file.SaveAs(Server.MapPath(Path.Combine("~/App_Data/", fname)));
    }
}

3
@mathieu, pena que sua variante usa runat="server", não é independente das coisas do servidor ASP.NET
Segredo

e se houver mais de 1 entrada e você quiser funções separadas executadas com os dois conjuntos de arquivos.
Neville Nazerane

ao usá-lo para fazer upload de vários arquivos, ele retorna o mesmo nome de arquivo para todos os arquivos e, portanto, salva o primeiro arquivo n número de vezes. Alguma ideia de como superar isso?
sohaiby

@Martina Verifique este snippet de código para salvar vários arquivos
sohaiby

1
@DanielJ. Não há como não usar code-behind se você for fazer algo com o arquivo posteriormente, ou seja, armazená-lo em um banco de dados. Claro, você poderia usar JavaScript direto para pegar a entrada e o arquivo: var fileUploaded = document.getElementById("myFile").files[0];e você pode até mesmo obter os bytes usando readAsArrayBuffer: stackoverflow.com/questions/37134433/… - mas o que você vai fazer com todos esses bytes do lado do cliente? O OP deseja evitar completamente a comunicação do lado do servidor de controle e não do ASP .NET. -1 para você.
vapcguy

40

Aqui está uma solução sem depender de nenhum controle do lado do servidor, assim como o OP descreveu na pergunta.

Código HTML do cliente:

<form action="upload.aspx" method="post" enctype="multipart/form-data">
    <input type="file" name="UploadedFile" />
</form>

Método Page_Load de upload.aspx:

if(Request.Files["UploadedFile"] != null)
{
    HttpPostedFile MyFile = Request.Files["UploadedFile"];
    //Setting location to upload files
    string TargetLocation = Server.MapPath("~/Files/");
    try
    {
        if (MyFile.ContentLength > 0)
        {
            //Determining file name. You can format it as you wish.
            string FileName = MyFile.FileName;
            //Determining file size.
            int FileSize = MyFile.ContentLength;
            //Creating a byte array corresponding to file size.
            byte[] FileByteArray = new byte[FileSize];
            //Posted file is being pushed into byte array.
            MyFile.InputStream.Read(FileByteArray, 0, FileSize);
            //Uploading properly formatted file to server.
            MyFile.SaveAs(TargetLocation + FileName);
        }
    }
    catch(Exception BlueScreen)
    {
        //Handle errors
    }
}

Cuidado com a chamada HTTPWebRequest enviando o caminho completo do arquivo em MyFile.FileName. A chamada do WebClient apenas envia o nome do arquivo. O HTTPWebRequest fará com que o MyFile.SaveAs falhe. Apenas horas perdidas perseguindo um cliente trabalhando e outro não.
Bob Clegg

Eu apenas usei em Request.Files[0]vez de Request.Files["UploadedFile"]e enquanto o OP estava usando ASP .NET puro e não MVC, se alguém quiser usar isso para MVC, você só precisa em HttpPostedFileBasevez de HttpPostedFile.
vapcguy

23

Você terá que definir o enctypeatributo de formpara multipart/form-data; então você pode acessar o arquivo carregado usando a HttpRequest.Filescoleção.


Meu formulário de servidor estava em uma página mestra e não pude adicionar multipart / form-data (desde então, estaria em todas as páginas). Uma solução alternativa rápida e suja era adicionar um controle FileUpload oculto à página. WebForms então adicionou os dados multipart / form automaticamente. Tive que fazer isso porque estava usando uma entrada de arquivo com Angular2 e não podia usar um controle de servidor em um modelo de componente.
Jason

9

use o controle HTML com um atributo de servidor runat

 <input id="FileInput" runat="server" type="file" />

Então, em asp.net Codebehind

 FileInput.PostedFile.SaveAs("DestinationPath");

Existem também algumas opções de terceiros que mostrarão o progresso se você se interessar


3
Novamente, isso está se transformando em um controle de servidor. ;)
ahwm

@ahwm O OP queria evitar o controle FileUpload do ASP .NET ( <asp:FileUpload ID="fileUpload1" runat="server"></asp:FileUpload>) Isso é diferente de dizer para não colocar um runat=serverem um inputcampo.
vapcguy

1
Acho que isso significa que eles não querem usar controles ASP.NET. Que inclui o HtmlInputFilecontrole.
ahwm

8

Sim, você pode conseguir isso pelo método de postagem Ajax. no lado do servidor, você pode usar httphandler. Portanto, não estamos usando nenhum controle de servidor de acordo com sua necessidade.

com ajax você também pode mostrar o progresso do upload.

você terá que ler o arquivo como um fluxo de entrada.

using (FileStream fs = File.Create("D:\\_Workarea\\" + fileName))
    {
        Byte[] buffer = new Byte[32 * 1024];
        int read = context.Request.GetBufferlessInputStream().Read(buffer, 0, buffer.Length);
        while (read > 0)
        {
            fs.Write(buffer, 0, read);
            read = context.Request.GetBufferlessInputStream().Read(buffer, 0, buffer.Length);
        }
    } 

Código de amostra

function sendFile(file) {              
        debugger;
        $.ajax({
            url: 'handler/FileUploader.ashx?FileName=' + file.name, //server script to process data
            type: 'POST',
            xhr: function () {
                myXhr = $.ajaxSettings.xhr();
                if (myXhr.upload) {
                    myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
                }
                return myXhr;
            },
            success: function (result) {                    
                //On success if you want to perform some tasks.
            },
            data: file,
            cache: false,
            contentType: false,
            processData: false
        });
        function progressHandlingFunction(e) {
            if (e.lengthComputable) {
                var s = parseInt((e.loaded / e.total) * 100);
                $("#progress" + currFile).text(s + "%");
                $("#progbarWidth" + currFile).width(s + "%");
                if (s == 100) {
                    triggerNextFileUpload();
                }
            }
        }
    }

2
Talvez você deva adicionar a dica para adicionar e fs.close()todo o resto pode acabar em arquivos ilegíveis, já que eles permanecem abertos de alguma forma no IIS.
mistapink de

@mistapink O fluxo do arquivo não é fechado quando a execução deixa o bloco de uso?
Sebi,

@Sebi parece que há quase 3 anos não. Não tentei por um longo tempo, então não posso dar uma resposta definitiva aqui. Sinto muito.
mistapink

4

A coleção Request.Files contém todos os arquivos carregados com o seu formulário, independentemente de serem provenientes de um controle FileUpload ou escrito manualmente <input type="file"> .

Portanto, você pode simplesmente escrever uma tag de entrada de arquivo simples e antiga no meio de seu formulário da Web e, em seguida, ler o arquivo carregado da coleção Request.Files.


4

Como outros já responderam, o Request.Files é um HttpFileCollection que contém todos os arquivos que foram postados, você só precisa pedir a esse objeto o arquivo assim:

Request.Files["myFile"]

Mas o que acontece quando há mais de uma marcação de entrada com o mesmo nome de atributo:

Select file 1 <input type="file" name="myFiles" />
Select file 2 <input type="file" name="myFiles" />

No lado do servidor, o código anterior Request.Files ["myFile"] retorna apenas um objeto HttpPostedFile em vez dos dois arquivos. Eu vi no .net 4.5 um método de extensão chamado GetMultiple, mas para as versões anteriores ele não existe, por isso proponho o método de extensão como:

public static IEnumerable<HttpPostedFile> GetMultiple(this HttpFileCollection pCollection, string pName)
{
        for (int i = 0; i < pCollection.Count; i++)
        {
            if (pCollection.GetKey(i).Equals(pName))
            {
                yield return pCollection.Get(i);
            }
        }
}

Este método de extensão retornará todos os objetos HttpPostedFile que possuem o nome "myFiles" em HttpFileCollection, se houver.


2

Controle HtmlInputFile

Eu usei isso o tempo todo.


2
Isso requer adição, o runat="server"que essencialmente o transforma em um controle de servidor, que eles não queriam usar.
ahwm

@ahwm Não, o OP não queria usar o controle específico do ASP .NET FileUpload. Isso é diferente de dizer que eles não queriam usar um controle do lado do servidor, em geral.
vapcguy


0
//create a folder in server (~/Uploads)
 //to upload
 File.Copy(@"D:\CORREO.txt", Server.MapPath("~/Uploads/CORREO.txt"));

 //to download
             Response.ContentType = ContentType;
             Response.AppendHeader("Content-Disposition", "attachment;filename=" + Path.GetFileName("~/Uploads/CORREO.txt"));
             Response.WriteFile("~/Uploads/CORREO.txt");
             Response.End();
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.