Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > VB .NET > Загрузка файлов через POST через WebBrowser


Автор: DoKZ 9.7.2013, 19:03
Занялся проектом на VB.NET и подошел к нему достаточно странно. 
Данные на сервере почти не меняются и не обрабатываются, да и я слаб в сокетных соединениях на VB (я знаю все языки программирования, но по чуть-чуть), поэтому писать сервер-приложение стало лень, ASP.NET тоже не догнал. Поэтому "сервер" представляет из себя несколько PHP-файлов, лежащих на хостинге, которые генерируют текстовый ответ (не HTML, без тэгов), а программа уже парсит этот ответ. Например, файл "/UserHasAccessToTest.php?login=dokz&testid=50" выдаст просто plain "YES" или "NO", что попадёт в System.Net.WebResponse, а оттуда в булеан и т д.
Вопрос 1: Это, вообще, нормальный подход или это совсем извращение и стоит всё по-нормальному написать?  smile 

Вопрос 2: Теперь появилась такая проблема. Мне нужно залить файл на сервер. FTP нет. Предположим, это Денвер. 
Я создал форму с стандартным POST-запросом для аплоада. Теперь мне надо на скрытой форме с компонентом WebBrowser открыть эту страницу, указать как-то путь к файлу и нажать "аплоад". Я реализовал это с помощью реальной формы и имитации движения мыши и кликов через Cursor, но смотрится ужасно.

Спасибо заранее за ответ smile

Автор: diadiavova 9.7.2013, 22:51
Цитата(DoKZ @  9.7.2013,  20:03 Найти цитируемый пост)
Это, вообще, нормальный подход или это совсем извращение и стоит всё по-нормальному написать? 

Обычно в таких случаях создается либо веб-служба, либо WCF-служба. Можно в рамках ASP.Net MVC создать вебапи, но то что делаешь ты может сойти только в очень простых случаях. Порекомендовать что-то для пхп я не могу, так как не знаю какие там есть возможности, это надо в соответствующем разделе спрашивать. 
Является ли это извращением? На мой взгляд да, но это не значит, что такой подход нельзя использовать. Если он решает твои задачи и является наиболее простым в реализации, то возможно это не так уж и плохо. Проблему я здесь вижу только в том, что задачи могут измениться и логику приложения придется усложнить настолько, что проще будет переписать и сделать все нормально.
Парсить собственный текстовый формат - точно не есть хорошо, обычно для этих целей используется XML или JSON, последний удобнее для аякса на вебстраницах, но фреймворк располагает инструментами для работы с ним, так что тоже можно использовать.
Цитата(DoKZ @  9.7.2013,  20:03 Найти цитируемый пост)
Предположим, это Денвер.

Если ты не имеешь в виду город в США, то видимо надо пояснить что это.
Цитата(DoKZ @  9.7.2013,  20:03 Найти цитируемый пост)
Я создал форму с стандартным POST-запросом для аплоада. Теперь мне надо на скрытой форме с компонентом WebBrowser открыть эту страницу, указать как-то путь к файлу и нажать "аплоад". Я реализовал это с помощью реальной формы и имитации движения мыши и кликов через Cursor, но смотрится ужасно.

Звучит не менее ужасно. Все что делает браузер можно сделать WebRequest'ом, для этого надо изучить что отправляет на сервер браузер при отправке формы с аттачем. Для этого погугли что такое тип содержимого multipart/form-data и как в нем организованы данные, сформировать программно такой запрос вполне реально, а то и вовсе можно готовую библиотеку поискать, которая это делает.
В веббраузере вполне можно кликнуть по кнопке программно, а еще лучше программно отправить форму, ну что-то типа
Код

WebbBrowser1.Document.GetElementById("myForm").DomElement.submit()
Код приблизительный ессно, но я думаю понятный.

Автор: DoKZ 10.7.2013, 00:02
Под Денвером имел в виду локальный сервер (http://denwer.ru)  smile 
Проблема решена сама собой. Точнее, благодаря гуглу и западным форумам. 
Всё оказалось очень просто, как Вы и говорили - WebRequest с нужными параметрами. 
Самой большой проблемой было понять как передать имя поля (которое здесь userfile):
Код

$_FILES["userfile"]["tmp_name"]

Оказывается, вот так:
Код

header.Append("Content-Disposition: form-data; name=""userfile"";")


Спасибо Вам большое за ответ, очень помогли, почитал про всё это, вроде чуть больше понял.

P.S. Может кому понадобится, полный код функции, полезная штука. Передаются путь к файлу и урл. Возвращает ответ, лучше сделать не String, а потоком, но мне было не критично.
Код

Public Function UploadFile(ByVal FilePath As String, ByVal URL As String) As String
        Dim boundary As String = IO.Path.GetRandomFileName
        Dim header As New System.Text.StringBuilder()

        header.AppendLine("--" & boundary)
        header.Append("Content-Disposition: form-data; name=""userfile"";")
        header.AppendFormat("filename=""{0}""", IO.Path.GetFileName(FilePath))
        header.AppendLine()
        header.AppendLine("Content-Type: application/octet-stream")
        header.AppendLine()

        Dim headerbytes() As Byte = System.Text.Encoding.UTF8.GetBytes(header.ToString)
        Dim endboundarybytes() As Byte = System.Text.Encoding.ASCII.GetBytes(vbNewLine & "--" & boundary & "--" & vbNewLine)

        Dim req As Net.HttpWebRequest = Net.HttpWebRequest.Create(URL)
        req.ContentType = "multipart/form-data; boundary=" & boundary
        req.ContentLength = headerbytes.Length + New IO.FileInfo(FilePath).Length + endboundarybytes.Length
        req.Method = "POST"

        Dim s As IO.Stream = req.GetRequestStream
        s.Write(headerbytes, 0, headerbytes.Length)
        Dim filebytes() As Byte = My.Computer.FileSystem.ReadAllBytes(FilePath)
        s.Write(filebytes, 0, filebytes.Length)
        s.Write(endboundarybytes, 0, endboundarybytes.Length)
        s.Close()

        'Get the responds of these request
        Dim resp As Net.HttpWebResponse = req.GetResponse()
        Dim sresp As IO.Stream = resp.GetResponseStream()
        Dim bytes(80000) As Byte
        sresp.Read(bytes, 0, 80000)

        Return System.Text.Encoding.ASCII.GetChars(bytes)
    End Function

Автор: shurikv 10.7.2013, 06:26
А a делаю так. Файл PHP на сервере (upload.php):
Код

<?php
if (isset($_FILES['file'])) {
    if ($_FILES['file']['error'] == 0 && $_FILES['file']['size'] > 0) { 
        $path = basename($_FILES['file']['name']);
        if (@move_uploaded_file($_FILES['file']['tmp_name'], $path)) echo 'OK';
    }
}
На VB.NET (самый простой вариант)
Код

My.Computer.Network.UploadFile ("C:\file.txt", "http://www.mysait.ru/upload.php","","",True,500)
При этом выходит маленькое окошечко, где бежит процесс.
Есть еще два варианта через WebClient: 
1 - синхронный (программа ждет окончания процесса)
Код

Dim myWebClient As New WebClient()
Dim responseArray As Byte() = myWebClient.UploadFile(uriString, "POST", fileName)
Console.WriteLine(ControlChars.Cr + "Response Received.The contents of the file uploaded are: " & ControlChars.Cr & "{0}", System.Text.Encoding.ASCII.GetString(responseArray))
2 - ассинхронный (можно отслеживать процесс загрузки и отлавливать конец процесса)
Код

WebClient.UploadFileAsync - метод (uriString, "POST", fileName)
события:
UploadProgressChanged - изменился процент загрузки
UploadFileCompleted - конец загрузки файла

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)