Caricamento di file in ASP.net senza utilizzare il controllo del server FileUpload


99

Come posso ottenere un modulo Web ASP.net (v3.5) per inviare un file utilizzando un vecchio semplice <input type="file" />?

Non mi interessa utilizzare il controllo server FileUpload di ASP.net.

Risposte:


133

Nel tuo 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>

Nel codice dietro:

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, peccato che la tua variante usi runat="server", non è indipendente dalla roba del server di ASP.NET
Segreto

cosa succede se ci sono più di 1 input e si desidera eseguire funzioni separate con entrambi i set di file.
Neville Nazerane,

mentre lo si utilizza per caricare più file, restituisce lo stesso nome file per tutti i file e quindi salva il primo file n numero di volte. Qualche idea su come superarlo?
sohaiby

@Martina Controlla questo snippet di codice per il salvataggio di più file
sohaiby

1
@DanielJ. Non c'è modo possibile per non farlo utilizzare il code-behind se in seguito farai qualcosa con il file, ad esempio archiviandolo in un database. Certo, potresti usare JavaScript diretto per prendere l'input e il file: var fileUploaded = document.getElementById("myFile").files[0];e puoi persino ottenere i byte usando readAsArrayBuffer: stackoverflow.com/questions/37134433/… - ma cosa farai con tutti quei byte lato client? L'OP vuole evitare del tutto la comunicazione lato server e controllo ASP .NET. -1 a te.
vapcguy

40

Ecco una soluzione senza fare affidamento su alcun controllo lato server, proprio come OP ha descritto nella domanda.

Codice HTML lato client:

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

Page_Load metodo di 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
    }
}

Fai attenzione alla chiamata HTTPWebRequest che invia il percorso completo del file in MyFile.FileName. La chiamata WebClient invia solo il nome del file. HTTPWebRequest causerà il fallimento di MyFile.SaveAs. Solo ore sprecate inseguendo un cliente che lavora e un cliente no.
Bob Clegg

Ho appena usato al Request.Files[0]posto di Request.Files["UploadedFile"]e mentre l'OP utilizzava ASP .NET e non MVC, se qualcuno vuole usarlo per MVC, è sufficiente HttpPostedFileBaseinvece di HttpPostedFile.
vapcguy

23

Dovrai impostare l' enctypeattributo del formto multipart/form-data; quindi puoi accedere al file caricato utilizzando la HttpRequest.Filesraccolta.


Il mio modulo del server era su una pagina master e non potevo aggiungere multipart / form-data (da allora sarebbe su ogni pagina). Una soluzione rapida e sporca era aggiungere un controllo FileUpload nascosto alla pagina. WebForms ha quindi aggiunto automaticamente i dati multipart / form. Ho dovuto farlo perché stavo usando un input di file con Angular2 e non potevo usare un controllo server in un modello di componente.
Jason

9

utilizzare il controllo HTML con un attributo del server runat

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

Quindi in asp.net Codebehind

 FileInput.PostedFile.SaveAs("DestinationPath");

Ci sono anche alcune opzioni di terze parti che mostreranno i progressi se sei interessato


3
Di nuovo, questo lo sta trasformando in un controllo server. ;)
ahwm

@ahwm L'OP voleva evitare il controllo ASP .NET FileUpload ( <asp:FileUpload ID="fileUpload1" runat="server"></asp:FileUpload>) Questo è diverso dal dire di non mettere un runat=serverin un inputcampo.
vapcguy

1
Lo prendo a significare che non vogliono usare i controlli ASP.NET. Che include il HtmlInputFilecontrollo.
ahwm

8

Sì, puoi ottenerlo con il metodo ajax post. lato server puoi usare httphandler. Quindi non stiamo utilizzando alcun controllo del server secondo le tue esigenze.

con ajax puoi anche mostrare l'avanzamento del caricamento.

dovrai leggere il file come inputstream.

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

Codice di esempio

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
Forse dovresti aggiungere il suggerimento per aggiungere fs.close()tutto il resto potrebbe finire in file illeggibili poiché rimangono in qualche modo aperti all'interno di IIS.
mistapink

@mistapink Il flusso di file non è chiuso quando l'esecuzione lascia il blocco using?
Sebi

@Sebi sembra che quasi 3 anni fa non fosse così. Non l'ho provato per molto tempo, quindi non posso dare una risposta definitiva qui. Mi dispiace.
mistapink

4

La raccolta Request.Files contiene tutti i file caricati con il modulo, indipendentemente dal fatto che provengano da un controllo FileUpload o da un <input type="file"> .

Quindi puoi semplicemente scrivere un semplice vecchio tag di input del file nel mezzo del tuo WebForm, quindi leggere il file caricato dalla raccolta Request.Files.


4

Come altri hanno risposto, Request.Files è un HttpFileCollection che contiene tutti i file che sono stati pubblicati, devi solo chiedere a quell'oggetto il file in questo modo:

Request.Files["myFile"]

Ma cosa succede quando ci sono più markup di input con lo stesso nome di attributo:

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

Sul lato server il codice precedente Request.Files ["myFile"] restituisce un solo oggetto HttpPostedFile invece dei due file. Ho visto su .net 4.5 un metodo di estensione chiamato GetMultiple ma per le versioni precedenti non esiste, del resto propongo il metodo di estensione come:

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

Questo metodo di estensione restituirà tutti gli oggetti HttpPostedFile che hanno il nome "myFiles" in HttpFileCollection, se presente.


2

Controllo HtmlInputFile

L'ho usato tutto il tempo.


2
Ciò richiede l'aggiunta runat="server"che essenzialmente lo trasforma in un controllo server, che non volevano usare.
ahwm

@ahwm No, l'OP non voleva utilizzare il controllo FileUpload ASP .NET specifico. Questo è diverso dal dire che non volevano usare un controllo lato server, in generale.
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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.