Загрузка файлов в ASP.net без использования серверного элемента управления FileUpload

99

Как я могу получить веб-форму ASP.net (v3.5) для публикации файла с помощью простого старого <input type="file" />?

Меня не интересует использование серверного элемента управления ASP.net FileUpload.

Ронни Оверби
источник

Ответы:

133

В вашем 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>

В коде позади:

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, жаль, что ваш вариант действительно используется runat="server", он не зависит от серверного материала ASP.NET
Secret
что, если имеется более 1 входа, и вы хотите, чтобы с обоими наборами файлов выполнялись отдельные функции.
Невилл Назеран
при использовании его для загрузки нескольких файлов он возвращает одно и то же имя файла для всех файлов и, следовательно, сохраняет первый файл n раз. Есть идеи, как это преодолеть?
sohaiby
@Martina Проверьте этот фрагмент кода для сохранения нескольких файлов
sohaiby
1
@DanielJ. Невозможно не использовать код программной части, если вы собираетесь потом что-то делать с файлом, то есть сохранять его в базе данных. Конечно, вы можете использовать прямой JavaScript для получения входных данных и файла: var fileUploaded = document.getElementById("myFile").files[0];и вы даже можете получить байты, используя readAsArrayBuffer: stackoverflow.com/questions/37134433/… - но что вы собираетесь делать со всеми этими байтами на стороне клиента? OP хочет полностью избежать взаимодействия ASP .NET на стороне элемента управления, а не на стороне сервера. -1 тебе.
vapcguy
40

Вот решение, не полагающееся на какой-либо элемент управления на стороне сервера, как и OP, описанный в вопросе.

Клиентский HTML-код:

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

Page_Load метод 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
    }
}
Айджан Яшит
источник
Следите за вызовом HTTPWebRequest, отправляющим полный путь к файлу в MyFile.FileName. Вызов WebClient просто отправляет имя файла. HTTPWebRequest приведет к сбою MyFile.SaveAs. Просто потраченные впустую часы в погоне за одним работающим клиентом, а другим - нет.
Боб Клегг
Я просто использовал Request.Files[0]вместо, Request.Files["UploadedFile"]и пока OP использовал простой ASP .NET, а не MVC, если кто-то хочет использовать это для MVC, вам просто нужно HttpPostedFileBaseвместо HttpPostedFile.
vapcguy
23

Вам нужно будет установить enctypeатрибут formдля multipart/form-data; тогда вы можете получить доступ к загруженному файлу, используя HttpRequest.Filesколлекцию.

csgero
источник
Моя серверная форма была на главной странице, и я не мог добавлять multipart / form-data (с тех пор они будут на каждой странице). Быстрый обходной путь - добавить на страницу скрытый элемент управления FileUpload. Затем WebForms автоматически добавил данные multipart / form. Мне пришлось это сделать, потому что я использовал ввод файла с Angular2 и не мог использовать серверный элемент управления в шаблоне компонента.
Джейсон
9

использовать элемент управления HTML с атрибутом сервера runat

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

Затем в asp.net Codebehind

 FileInput.PostedFile.SaveAs("DestinationPath");

Есть также несколько сторонних вариантов, которые покажут прогресс, если вам интересно

cgreeno
источник
3
Опять же, это превращает его в серверный элемент управления. ;)
ahwm 03
@ahwm OP хотел избежать использования элемента управления ASP .NET FileUpload ( <asp:FileUpload ID="fileUpload1" runat="server"></asp:FileUpload>). Это отличается от того, чтобы сказать, что нельзя помещать a runat=serverв inputполе.
vapcguy
1
Я понимаю, что они не хотят использовать элементы управления ASP.NET. Что включает в себя HtmlInputFilecontrol.
ahwm
8

Да, вы можете добиться этого с помощью метода сообщения ajax. на стороне сервера вы можете использовать httphandler. Поэтому мы не используем никаких серверных элементов управления в соответствии с вашими требованиями.

с помощью ajax вы также можете показать прогресс загрузки.

вам нужно будет прочитать файл как входной поток.

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

Образец кода

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
Возможно, вам стоит добавить подсказку, чтобы fs.close()все остальное могло оказаться в нечитаемых файлах, поскольку они каким-то образом остаются открытыми в IIS.
mistapink
@mistapink Не закрывается ли файловый поток, когда выполнение выходит из используемого блока?
Себи
@Sebi, кажется, почти 3 года назад этого не было. Давно не пробовал, поэтому однозначного ответа здесь дать не могу. Я прошу прощения.
mistapink
4

Коллекция Request.Files содержит любые файлы, загруженные с вашей формой, независимо от того, пришли ли они из элемента управления FileUpload или вручную написанного <input type="file"> .

Таким образом, вы можете просто написать простой старый тег ввода файла в середине вашей WebForm, а затем прочитать файл, загруженный из коллекции Request.Files.

Дэвид
источник
4

Поскольку у других есть ответ, Request.Files - это HttpFileCollection, который содержит все файлы, которые были опубликованы, вам нужно только запросить этот объект для файла следующим образом:

Request.Files["myFile"]

Но что произойдет, если существует более одной разметки ввода с одинаковым именем атрибута:

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

На стороне сервера предыдущий код Request.Files ["myFile"] возвращает только один объект HttpPostedFile вместо двух файлов. Я видел в .net 4.5 метод расширения под названием GetMultiple, но для предыдущих версий он не существует, в этом отношении я предлагаю метод расширения как:

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

Этот метод расширения вернет все объекты HttpPostedFile, имеющие имя «myFiles» в HttpFileCollection, если таковые существуют.

Джои О
источник
2

Элемент управления HtmlInputFile

Я использовал это все время.

Lurker действительно
источник
2
Это требует добавления, runat="server"которое по сути превращает его в серверный элемент управления, который они не хотели использовать.
ahwm 03
@ahwm Нет, OP не хотел использовать конкретный элемент управления ASP .NET FileUpload. Это отличается от того, чтобы сказать, что они вообще не хотят использовать элемент управления на стороне сервера.
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();
Жан-Пьер Йенке
источник