none
Отправка данных POST C# RRS feed

  • Вопрос

  • Здравствуйте, есть некий сервис по хранению картинок, с очень простым API. Вот всё его описание:

    Параметры для запроса:

    userfile - файл картинки. Должен быть передан как HTTP POST в формате multipart/form-data. Обязательный параметр.

    user - Имя пользоваетеля. Не обязательное поле.

    passwd - Пароль. Не обязательное поле.

    Последние два поля служат для загрузки изображений в свой профиль.

    Все данные скрипт отдаёт в формате XML.

     

    Есть код, приложения, но сервер почему то всегда откликается отрицательно (т.е. отказывается вернуть ссылки на изображения, а пишет что файл не выбран). Что тут не так?

     

    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    
    namespace Black_Uploader
    {
        class Program
        {
            static void Main(string[] args)
            {
                WebRequest send = WebRequest.Create(@"http://api.imageban.ru/upload_api.php");
                send.Method = "POST";
                send.ContentType = "multipart/form-data";
    
                StringBuilder sendData = new StringBuilder();
                using (FileStream img = new FileStream("D:\\s.png", FileMode.Open))
                {
                    sendData.Append("userfile="+img.ToString());
                }
    
                byte[] byteData = Encoding.GetEncoding(1251).GetBytes(sendData.ToString());
                send.ContentLength = byteData.Length;
                using (Stream sendStream = send.GetRequestStream())
                {
                    sendStream.Write(byteData, 0, byteData.Length);
                }
    
                using (WebResponse result = send.GetResponse())
                {
                    StreamReader reader = new StreamReader(result.GetResponseStream());
                    //XDocument res = XDocument.Parse(reader.ReadToEnd());
                    //res.Save("res.xml");
                    Console.WriteLine(reader.ReadToEnd());
                }
                Console.ReadKey();
            }
        }
    }
    


    MSDN AA User
    19 января 2012 г. 21:55

Ответы

  • Здравствуйте.

    Воспользуйтесь таким методом загрузки файла:

        public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc)
            {
                Console.WriteLine(string.Format("Uploading {0} to {1}", file, url));
                string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
    
                HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
                wr.ContentType = "multipart/form-data; boundary=" + boundary;
                wr.Method = "POST";
                wr.KeepAlive = true;
                wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
    
                Stream rs = wr.GetRequestStream();
    
                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                foreach (string key in nvc.Keys)
                {
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
                    string formitem = string.Format(formdataTemplate, key, nvc[key]);
                    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                    rs.Write(formitembytes, 0, formitembytes.Length);
                }
                rs.Write(boundarybytes, 0, boundarybytes.Length);
    
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                string header = string.Format(headerTemplate, paramName, file, contentType);
                byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                rs.Write(headerbytes, 0, headerbytes.Length);
    
                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    rs.Write(buffer, 0, bytesRead);
                }
                fileStream.Close();
    
                byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                rs.Write(trailer, 0, trailer.Length);
                rs.Close();
    
                WebResponse wresp = null;
                try
                {
                    wresp = wr.GetResponse();
                    Stream stream2 = wresp.GetResponseStream();
                    StreamReader reader2 = new StreamReader(stream2);
                    Console.WriteLine(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error uploading file", ex);
                    if (wresp != null)
                    {
                        wresp.Close();
                        wresp = null;
                    }
                }
                finally
                {
                    wr = null;
                }
            }
    

    Как его использовать:

                NameValueCollection nvc = new NameValueCollection();
                //nvc.Add("user", "user");
                //nvc.Add("passwd", "passwd");
                HttpUploadFile("http://api.imageban.ru/upload_api.php", @"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg", "userfile", "image/jpeg", nvc);
    

     


    Для связи [mail]
    • Помечено в качестве ответа asdfxcbneftyherwe 20 января 2012 г. 8:58
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 8:10
    20 января 2012 г. 8:42
  • Можно. Этот кусок отвечает за считывания файла и запись в поток запроса

                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = fileStream.Read(buffer, 0, buffer)) != 0) 
                {
                   rs.Write(buffer, 0, bytesRead); 
                }
                fileStream.Close();
    

    Получите массив байт из MemoryStream с помощью метода ToArray() и запишите его в rs:

    byte[] bytes = memoryStream.ToArray();
    rs.Write(bytes, 0, bytes.Length);
    

    Для связи [mail]
    • Помечено в качестве ответа asdfxcbneftyherwe 20 января 2012 г. 14:42
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 8:10
    20 января 2012 г. 14:08
  •  

     using (MemoryStream fileStream = new MemoryStream())
                    {
                        byte[] buffer = new byte[4096];
                        int bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            rs.Write(file, 0, file.Length );
                        }
                    }
    
    

     

     

    Из всего этого вам нужна только строка

    rs.Write(file, 0, file.Length );

    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 15:15
    20 января 2012 г. 22:18
    Отвечающий
  • Всё, разобрался с проблемой. Достаточно было в строчке:

    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
    string header = string.Format(headerTemplate, paramName, file, contentType);
    
    


    переменную file заменить на что нибудь, оканчивающееся на .png (сервер проверяет допустимость типа по расширению >.< )  Результат таков:

    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
    string header = string.Format(headerTemplate, paramName, "picture.png", contentType);
    

    Всем спасибо за помощь.


    MSDN AA User
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 15:14
    21 января 2012 г. 15:14

Все ответы

  • Здравствуйте.

    Воспользуйтесь таким методом загрузки файла:

        public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc)
            {
                Console.WriteLine(string.Format("Uploading {0} to {1}", file, url));
                string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
    
                HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
                wr.ContentType = "multipart/form-data; boundary=" + boundary;
                wr.Method = "POST";
                wr.KeepAlive = true;
                wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
    
                Stream rs = wr.GetRequestStream();
    
                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                foreach (string key in nvc.Keys)
                {
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
                    string formitem = string.Format(formdataTemplate, key, nvc[key]);
                    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                    rs.Write(formitembytes, 0, formitembytes.Length);
                }
                rs.Write(boundarybytes, 0, boundarybytes.Length);
    
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                string header = string.Format(headerTemplate, paramName, file, contentType);
                byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                rs.Write(headerbytes, 0, headerbytes.Length);
    
                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    rs.Write(buffer, 0, bytesRead);
                }
                fileStream.Close();
    
                byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                rs.Write(trailer, 0, trailer.Length);
                rs.Close();
    
                WebResponse wresp = null;
                try
                {
                    wresp = wr.GetResponse();
                    Stream stream2 = wresp.GetResponseStream();
                    StreamReader reader2 = new StreamReader(stream2);
                    Console.WriteLine(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error uploading file", ex);
                    if (wresp != null)
                    {
                        wresp.Close();
                        wresp = null;
                    }
                }
                finally
                {
                    wr = null;
                }
            }
    

    Как его использовать:

                NameValueCollection nvc = new NameValueCollection();
                //nvc.Add("user", "user");
                //nvc.Add("passwd", "passwd");
                HttpUploadFile("http://api.imageban.ru/upload_api.php", @"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg", "userfile", "image/jpeg", nvc);
    

     


    Для связи [mail]
    • Помечено в качестве ответа asdfxcbneftyherwe 20 января 2012 г. 8:58
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 8:10
    20 января 2012 г. 8:42
  • А можно модификацию метода, чтобы он вместо полного имени файла принимал поток MemoryStream с сохранённым там файлом?
    MSDN AA User
    20 января 2012 г. 13:29
  • Можно. Этот кусок отвечает за считывания файла и запись в поток запроса

                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = fileStream.Read(buffer, 0, buffer)) != 0) 
                {
                   rs.Write(buffer, 0, bytesRead); 
                }
                fileStream.Close();
    

    Получите массив байт из MemoryStream с помощью метода ToArray() и запишите его в rs:

    byte[] bytes = memoryStream.ToArray();
    rs.Write(bytes, 0, bytes.Length);
    

    Для связи [mail]
    • Помечено в качестве ответа asdfxcbneftyherwe 20 января 2012 г. 14:42
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 8:10
    20 января 2012 г. 14:08
  • class Loader
        {
            public static XDocument HttpUploadFile(string url, byte[] file, string paramName, string contentType, NameValueCollection nvc)
            {
                string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
    
                HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
                wr.ContentType = "multipart/form-data; boundary=" + boundary;
                wr.Method = "POST";
                wr.KeepAlive = true;
                wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
    
                using (Stream rs = wr.GetRequestStream())
                {
                    string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
    
                    foreach (string key in nvc.Keys)
                    {
                        rs.Write(boundarybytes, 0, boundarybytes.Length);
                        string formitem = string.Format(formdataTemplate, key, nvc[key]);
                        byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                        rs.Write(formitembytes, 0, formitembytes.Length);
                    }
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
    
                    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                    string header = string.Format(headerTemplate, paramName, file, contentType);
                    byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                    rs.Write(headerbytes, 0, headerbytes.Length);
    
                    using (MemoryStream fileStream = new MemoryStream())
                    {
                        byte[] buffer = new byte[4096];
                        int bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            rs.Write(file, 0, file.Length );
                        }
                    }
                
    
                    byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                    rs.Write(trailer, 0, trailer.Length);
                }
    
                using (HttpWebResponse result = (HttpWebResponse)wr.GetResponse())
                {
                    using (StreamReader reader = new StreamReader(result.GetResponseStream()))
                    {
                        return XDocument.Parse(reader.ReadToEnd());
                    }
                }
            }
        } 
    
    Ну вот что я делаю не так? Из главного метода программы вместо пути к файлу теперрь передаётся массив byte[] , извлечённых из MemoryStream. И всё равно получаю сообщение о неверном типе файла. >.<
    MSDN AA User
    20 января 2012 г. 18:00
  • А вот что происходит в главном методе:

    public MainWindow()
            {
                InitializeComponent();
                NameValueCollection nvc = new NameValueCollection();
                nvc.Add("user", "...");
                nvc.Add("passwd", "...");
                using (MemoryStream str = new MemoryStream())
                {
                    Bitmap bmp = new Bitmap(@"D:\test.bmp");
                    bmp.Save(str, ImageFormat.Png);
                    byte[] png = str.ToArray();
    
    
                    XDocument result = Loader.HttpUploadFile("http://api.imageban.ru/upload_api.php", png, "userfile", "image/jpeg", nvc);
                    string res = (string)result.Root.Element("url1") + "\n\n" + result.Root.Element("url2");
                    Clipboard.SetText(result.ToString());
                }
                Close();
            }
    


    MSDN AA User
    20 января 2012 г. 18:03
  • >byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

    Нельзя в Http использовать UTF-8.  Только ASCII.


    >bmp.Save(str, ImageFormat.Png);

    Сохраняете в png формате, а в content-type пишите что "image/jpeg"

     

    20 января 2012 г. 18:56
    Отвечающий
  • >Нельзя в Http использовать UTF-8. Только ASCII.

    Но в варианте Дмитрия работает же. Заменил на ASCII - небольшая разница, всё равно не хочет признавать пережаваемые данные картинкой.

    >>Сохраняете в png формате, а в content-type пишите что "image/jpeg"

    Упс, не заметил. Попробовал написать image/png а так же попробовал application/octet-stream- всё равно картинкой не признаёт.

     

    Всё таки я подозреваю, что ошибся именно где-то в

     

     

     using (MemoryStream fileStream = new MemoryStream())
                    {
                        byte[] buffer = new byte[4096];
                        int bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            rs.Write(file, 0, file.Length );
                        }
                    }
    
    

     

     

    При использовании метода в исходном виде от Дмитрия, всё работае на ура, но всё таки мне нужно не с диска читать файл.

    Исходный кусок:

     FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    rs.Write(buffer, 0, bytesRead);
                }
                fileStream.Close();
    


    MSDN AA User
    20 января 2012 г. 19:13
  •  

     using (MemoryStream fileStream = new MemoryStream())
                    {
                        byte[] buffer = new byte[4096];
                        int bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            rs.Write(file, 0, file.Length );
                        }
                    }
    
    

     

     

    Из всего этого вам нужна только строка

    rs.Write(file, 0, file.Length );

    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 15:15
    20 января 2012 г. 22:18
    Отвечающий
  •  

     using (MemoryStream fileStream = new MemoryStream())
                    {
                        byte[] buffer = new byte[4096];
                        int bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            rs.Write(file, 0, file.Length );
                        }
                    }
    
    

     

     

    Из всего этого вам нужна только строка

    rs.Write(file, 0, file.Length );


    Не хочет :(

     

    Главное окно:

     

    using System.Collections.Specialized;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Windows;
    using System.Xml.Linq;
    
    namespace Black_Uploader
    {
        /// <summary>
        /// Логика взаимодействия для MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                NameValueCollection nvc = new NameValueCollection();
                //nvc.Add("user", "...");
                //nvc.Add("passwd", "...");
                using (MemoryStream str = new MemoryStream())
                {
                    Bitmap bmp = new Bitmap(@"D:\test.bmp");
                    bmp.Save(str, ImageFormat.Png);
                    byte[] png = str.ToArray();
    
    
                    XDocument result = Loader.HttpUploadFile("http://api.imageban.ru/upload_api.php", png, "userfile", "image/png", nvc);
                    string res = (string)result.Root.Element("url1") + "\n\n" + result.Root.Element("url2");
                    Clipboard.SetText(result.ToString()); //для отладки юзать result.ToString(),  ибо проще
                }
                Close();
            }
        }
    }
    

    Сам класс:

     

     

    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.Net;
    using System.Xml.Linq;
    
    namespace Black_Uploader
    {
        class Loader
        {
            public static XDocument HttpUploadFile(string url, byte[] file, string paramName, string contentType, NameValueCollection nvc)
            {
                string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
    
                HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
                wr.ContentType = "multipart/form-data; boundary=" + boundary;
                wr.Method = "POST";
                wr.KeepAlive = true;
                wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
    
                using (Stream rs = wr.GetRequestStream())
                {
                    string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
    
                    foreach (string key in nvc.Keys)
                    {
                        rs.Write(boundarybytes, 0, boundarybytes.Length);
                        string formitem = string.Format(formdataTemplate, key, nvc[key]);
                        byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                        rs.Write(formitembytes, 0, formitembytes.Length);
                    }
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
    
                    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                    string header = string.Format(headerTemplate, paramName, file, contentType);
                    byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header);
                    rs.Write(headerbytes, 0, headerbytes.Length);
    
                    rs.Write(file, 0, file.Length );
    
                    byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                    rs.Write(trailer, 0, trailer.Length);
                }
    
                using (HttpWebResponse result = (HttpWebResponse)wr.GetResponse())
                {
                    using (StreamReader reader = new StreamReader(result.GetResponseStream()))
                    {
                        return XDocument.Parse(reader.ReadToEnd());
                    }
                }
            }
        }
    }
    
    

    И всё равно получаю ответ:

     

     

    <rsp stat="fail">
      <err code="103" msg="Invalid image type" />
    </rsp>
    

     

     


    MSDN AA User
    21 января 2012 г. 13:53
  • Сниффер информирует что серверу я отправляю следующие данные:  что тут не так?


    MSDN AA User
    21 января 2012 г. 14:46
  • Всё, разобрался с проблемой. Достаточно было в строчке:

    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
    string header = string.Format(headerTemplate, paramName, file, contentType);
    
    


    переменную file заменить на что нибудь, оканчивающееся на .png (сервер проверяет допустимость типа по расширению >.< )  Результат таков:

    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
    string header = string.Format(headerTemplate, paramName, "picture.png", contentType);
    

    Всем спасибо за помощь.


    MSDN AA User
    • Помечено в качестве ответа asdfxcbneftyherwe 21 января 2012 г. 15:14
    21 января 2012 г. 15:14