Téléchargement de fichiers dans ASP.net sans utiliser le contrôle serveur FileUpload

99

Comment puis-je obtenir un formulaire Web ASP.net (v3.5) pour publier un fichier en utilisant un ancien <input type="file" />?

Je ne suis pas intéressé par l'utilisation du contrôle serveur ASP.net FileUpload.

Ronnie Overby
la source

Réponses:

133

Dans votre 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>

Dans le code derrière:

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)));
    }
}
Mathieu
la source
3
@mathieu, dommage que votre variante utilise runat="server", elle n'est pas indépendante du serveur d'ASP.NET
Secret
que se passe-t-il s'il y a plus d'une entrée et que vous voulez que des fonctions distinctes soient exécutées avec les deux ensembles de fichiers.
Neville Nazerane
tout en l'utilisant pour télécharger plusieurs fichiers, il renvoie le même nom de fichier pour tous les fichiers et enregistre donc le premier fichier n nombre de fois. Une idée de comment s'en remettre?
sohaiby
@Martina Vérifiez cet extrait de code pour enregistrer plusieurs fichiers
sohaiby
1
@DanielJ. Il n'y a aucun moyen possible de ne pas utiliser le code-behind si vous allez faire quelque chose avec le fichier par la suite, c'est-à-dire le stocker dans une base de données. Bien sûr, vous pouvez utiliser du JavaScript simple pour récupérer l'entrée et le fichier: var fileUploaded = document.getElementById("myFile").files[0];et vous pouvez même obtenir les octets en utilisant readAsArrayBuffer: stackoverflow.com/questions/37134433/... - mais qu'allez -vous faire avec tous ces octets côté client? L'OP veut éviter complètement la communication côté serveur de contrôle ASP .NET. -1 à vous.
vapcguy
40

Voici une solution sans dépendre d'aucun contrôle côté serveur, tout comme OP l'a décrit dans la question.

Code HTML côté client:

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

Page Load.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
    }
}
Aycan Yaşıt
la source
Méfiez-vous de l'appel HTTPWebRequest envoyant le chemin complet du fichier dans MyFile.FileName. L'appel WebClient envoie simplement le nom du fichier. HTTPWebRequest entraînera l'échec de MyFile.SaveAs. Juste des heures perdues à courir après un client travaillant et un client non.
Bob Clegg
Je viens de l'utiliser à la Request.Files[0]place de Request.Files["UploadedFile"]et tandis que l'OP utilisait ASP .NET pur et non MVC, si quelqu'un veut l'utiliser pour MVC, vous avez juste besoin HttpPostedFileBasede HttpPostedFile.
vapcguy
23

Vous devrez définir l' enctypeattribut du formà multipart/form-data; alors vous pouvez accéder au fichier téléchargé en utilisant la HttpRequest.Filescollection.

csgero
la source
Mon formulaire serveur était sur une page maître et je ne pouvais pas ajouter des données multipart / form-data (depuis lors, ce serait sur chaque page). Une solution de contournement rapide et sale consistait à ajouter un contrôle FileUpload caché à la page. WebForms a ensuite ajouté automatiquement les données multipart / form. J'ai dû le faire parce que j'utilisais une entrée de fichier avec Angular2 et que je ne pouvais pas utiliser un contrôle serveur dans un modèle de composant.
Jason
9

utiliser le contrôle HTML avec un attribut serveur runat

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

Puis dans asp.net Codebehind

 FileInput.PostedFile.SaveAs("DestinationPath");

Il existe également des options de troisième partie qui afficheront la progression si vous êtes intéressé

cgreeno
la source
3
Encore une fois, cela en fait un contrôle de serveur. ;)
ahwm
@ahwm L'OP voulait éviter le contrôle ASP .NET FileUpload ( <asp:FileUpload ID="fileUpload1" runat="server"></asp:FileUpload>) C'est différent de dire de ne pas mettre un runat=serversur un inputchamp.
vapcguy
1
Je suppose que cela signifie qu'ils ne veulent pas utiliser les contrôles ASP.NET. Ce qui inclut le HtmlInputFilecontrôle.
ahwm
8

Oui, vous pouvez y parvenir par la méthode ajax post. côté serveur, vous pouvez utiliser httphandler. Nous n'utilisons donc aucun contrôle de serveur selon vos besoins.

avec ajax, vous pouvez également afficher la progression du téléchargement.

vous devrez lire le fichier en tant que flux d'entrée.

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

Exemple de code

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();
                }
            }
        }
    }
Samuel Joy
la source
2
Vous devriez peut-être ajouter un indice pour ajouter que fs.close()tout le reste pourrait finir dans des fichiers illisibles car ils restent en quelque sorte ouverts dans IIS.
Mistapink
@mistapink Le flux de fichiers n'est-il pas fermé lorsque l'exécution quitte le bloc using?
Sebi
@Sebi, il semble qu'il y a presque 3 ans, non. Je n'ai pas essayé pendant longtemps, donc je ne peux pas donner de réponse définitive ici. Je suis désolé.
Mistapink
4

La collection Request.Files contient tous les fichiers téléchargés avec votre formulaire, qu'ils proviennent d'un contrôle FileUpload ou d'un fichier <input type="file">.

Vous pouvez donc simplement écrire une ancienne balise d'entrée de fichier au milieu de votre WebForm, puis lire le fichier téléchargé depuis la collection Request.Files.

David
la source
4

Comme d'autres ont une réponse, Request.Files est un HttpFileCollection qui contient tous les fichiers qui ont été publiés, il vous suffit de demander à cet objet le fichier comme ceci:

Request.Files["myFile"]

Mais que se passe-t-il lorsqu'il y a plus d'un balisage d'entrée avec le même nom d'attribut:

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

Côté serveur, le code précédent Request.Files ["myFile"] ne renvoie qu'un seul objet HttpPostedFile au lieu des deux fichiers. J'ai vu sur .net 4.5 une méthode d'extension appelée GetMultiple mais pour les versions précédentes, elle n'existe pas, d'ailleurs je propose la méthode d'extension comme:

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

Cette méthode d'extension renverra tous les objets HttpPostedFile qui ont le nom «myFiles» dans HttpFileCollection s'il en existe.

Joey O
la source
2

Contrôle HtmlInputFile

Je l'ai utilisé tout le temps.

Lurker en effet
la source
2
Cela nécessite d'ajouter runat="server"ce qui le transforme essentiellement en un contrôle serveur, qu'ils ne voulaient pas utiliser.
ahwm
@ahwm Non, l'OP ne voulait pas utiliser le contrôle FileUpload ASP .NET spécifique. C'est différent de dire qu'ils ne voulaient pas utiliser de contrôle côté serveur, en général.
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();
Jean Pierre Yenque
la source