Портирование примера API-интерфейса TwitPic для C#, составные данные?
Так что Twitter изменил способ аутентификации на OAuth, и у меня, наконец, не было выбора, кроме как обновить свое приложение. У меня все работает в Твиттере (поэтому в моем приложении есть немного сохраненной информации об OAuth). Теперь я должен снова заставить работать API TwitPic. Нет библиотек, которые обрабатывают OAuth, который я нашел, поэтому я должен сделать это вручную, основываясь на том, что я нашел здесь:
http://dev.twitpic.com/docs/2/upload/
Думаю, я медленно, но верно добираюсь туда. Я ни в коем случае не являюсь экспертом в такого рода вещах, но я получил их другой вызов API: http://dev.twitpic.com/docs/2/users_show Это работает как шарм, хотя это не многочастный Данные с изображением там.
Я провел еще несколько исследований и понял, что хорошая среда Twitterizer, которую я использую для выполнения OAuth, выполняет для меня большую работу, а именно, подписание каждого запроса и требует только передачи нескольких битов моих OAuth-токенов. Итак, я заметил, что приведенный выше вызов метода для загрузки для TwitPic требует, чтобы его подписывали таким же образом, что является трудной частью: получить подпись и передать ее с помощью веб-запроса.
Это также то, что меня смущает, они говорят, что подпись, которую часть OAuth-эха передает в заголовке, кажется, это то же самое, что создание заголовка с использованием C# System.Net.WebHeaderCollection webhc = new System.Net.WebHeaderCollection();
?
Я знаю, что мне нужно сделать, каким-то образом получить запрос, вызванный моими токенами OAuth (сериализованными в JSON), создать сигнатуру, затем вызвать реальный API и передать ему три параметра (Сериализированный JSON): ключ, сообщение, файл.
Этот файл тоже сбивает меня с толку, так как он является резидентным файлом, я не уверен, как передать эти данные. У меня есть фрагмент кода из старой библиотеки TwitPic:
string fileContentType = "image/jpeg";//GetImageContentType(filename);
string fileHeader = String.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", "media", filename);
string fileData = Encoding.GetEncoding(encoding).GetString(binaryImageData);
contents.AppendLine(fileHeader);
contents.AppendLine(String.Format("Content-Type: {0}", fileContentType));
contents.AppendLine();
contents.AppendLine(fileData);
Проблема в том, что я пытаюсь сделать все это с помощью JSON. Создание fileContentType и т. Д. Для добавления всего этого к объекту содержимого StringBuilder кажется намного более ручной работой, чем мне нужно.
Я хотел бы, чтобы был TwitPic API для новой авторизации Twitter, где я передаю ему файл, сообщение и токены OAuth. Увы... любое управление в правильном направлении будет с благодарностью.
Для полноты выложен старый метод загрузки файла:
// <summary>
// Uploads the photo and sends a new Tweet
// </summary>
// <param name="binaryImageData">The binary image data.</param>
// <param name="tweetMessage">The tweet message.</param>
// <param name="filename">The filename.</param>
// <returns>Return true, if the operation was succeded.</returns>
public bool UploadPhoto(byte[] binaryImageData, string tweetMessage, string filename)
{
// Documentation: http://www.twitpic.com/api.do
string boundary = Guid.NewGuid().ToString();
string requestUrl = String.IsNullOrEmpty(tweetMessage) ? TWITPIC_UPLADO_API_URL : TWITPIC_UPLOAD_AND_POST_API_URL;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
string encoding = "iso-8859-1";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
request.Method = "POST";
string header = string.Format("--{0}", boundary);
string footer = string.Format("--{0}--", boundary);
StringBuilder contents = new StringBuilder();
contents.AppendLine(header);
string fileContentType = "image/jpeg";//GetImageContentType(filename);
string fileHeader = String.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", "media", filename);
string fileData = Encoding.GetEncoding(encoding).GetString(binaryImageData);
contents.AppendLine(fileHeader);
contents.AppendLine(String.Format("Content-Type: {0}", fileContentType));
contents.AppendLine();
contents.AppendLine(fileData);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "username"));
contents.AppendLine();
//contents.AppendLine(this.Username);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "password"));
contents.AppendLine();
//contents.AppendLine(this.Password.ToInsecureString());
if (!String.IsNullOrEmpty(tweetMessage))
{
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "message"));
contents.AppendLine();
contents.AppendLine(tweetMessage);
}
contents.AppendLine(footer);
byte[] bytes = Encoding.GetEncoding(encoding).GetBytes(contents.ToString());
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string result = reader.ReadToEnd();
XDocument doc = XDocument.Parse(result);
XElement rsp = doc.Element("rsp");
string status = rsp.Attribute(XName.Get("status")) != null ? rsp.Attribute(XName.Get("status")).Value : rsp.Attribute(XName.Get("stat")).Value;
return status.ToUpperInvariant().Equals("OK");
}
}
}
}
2 ответа
Исправление на самом деле очень просто. Проблема заключается в URL-адресе, который вы публикуете. В вашей строке:
private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://api.twitpic.com/1/uploadAndPost";
Вам нужно изменить на
private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://api.twitpic.com/1/uploadAndPost.xml";
ИЛИ ЖЕ
private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://api.twitpic.com/1/uploadAndPost.json";
Это даст вам тип ответа. Вам все еще нужно изменить часть кода, которая относится к тому, как вы используете XDocument для анализа результатов. В зависимости от URL, который вы используете выше, ответ будет либо XML, либо JSON. Ваш пример хорош для XML, однако код результатов не близок к тому, что вы ищете. Если вы хотите увидеть пример кода результата, вы можете просмотреть его по адресу http://dev.twitpic.com/docs/1/uploadAndPost/
Например, удалите следующие строки.
XElement rsp = doc.Element("rsp");
string status = rsp.Attribute(XName.Get("status")) != null ? rsp.Attribute(XName.Get("status")).Value : rsp.Attribute(XName.Get("stat")).Value;
mediaurl = rsp.Element("mediaurl").Value;
Затем заменить на
mediaurl = doc.Element("image").Element("url").Value;
Или вы можете просто запустить отладчик для JSON. Если кому-то это нужно и запрос, я могу сделать полный код.
Вот вариант обертки Twipli API, который позволяет вам сделать это. Единственная проблема, с которой я столкнулся, заключается в том, что я не могу заставить его отвечать с результатом сторонних манипуляций с возвращенными данными. Однако он отправляет сообщения в Twitter и загружает изображение правильно. Так много голов лучше, чем одна, поэтому, если вы найдете решение, дайте мне знать.
protected void Button1_Click(object sender, EventArgs e)
{
string ct = img.PostedFile.ContentType.ToString();
string usertoken = Session["usrToken"].ToString();
string userSecret = Session["usrSecret"].ToString();
string conkey = Session["ConsumerKey"].ToString();
string consecret = Session["ConsumerSecret"].ToString();
string twitkey = Session["twitpickey"].ToString();
string _m = m.Text; // This takes the Tweet to be posted
HttpPostedFile myFile = img.PostedFile;
string fileName = myFile.FileName.ToString();
int nFileLen = myFile.ContentLength;
byte[] myData = new byte[nFileLen];
myFile.InputStream.Read(myData, 0, nFileLen);
TwitPic tw = new TwitPic();
upres.Text = tw.UploadPhoto(myData, ct, _m, fileName, twitkey, usertoken, userSecret, conkey, consecret).ToString();
Response.Redirect("twittercb.aspx?oauth_verifier=none");
}
public class TwitPic
{
private const string TWITPIC_UPLADO_API_URL = "http://api.twitpic.com/2/upload";
private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://api.twitpic.com/1/uploadAndPost";
///
/// Uploads the photo and sends a new Tweet
///
/// <param name="binaryImageData">The binary image data.
/// <param name="tweetMessage">The tweet message.
/// <param name="filename">The filename.
/// Return true, if the operation was succeded.
public string UploadPhoto(byte[] binaryImageData, string ContentType, string tweetMessage, string filename, string tpkey, string usrtoken, string usrsecret, string contoken, string consecret)
{
string boundary = Guid.NewGuid().ToString();
string requestUrl = String.IsNullOrEmpty(tweetMessage) ? TWITPIC_UPLADO_API_URL : TWITPIC_UPLOAD_AND_POST_API_URL;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
string encoding = "iso-8859-1";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
request.Method = "POST";
string header = string.Format("--{0}", boundary);
string footer = string.Format("--{0}--", boundary);
StringBuilder contents = new StringBuilder();
contents.AppendLine(header);
string fileContentType = ContentType;
string fileHeader = String.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", "media", filename);
string fileData = Encoding.GetEncoding(encoding).GetString(binaryImageData);
contents.AppendLine(fileHeader);
contents.AppendLine(String.Format("Content-Type: {0}", fileContentType));
contents.AppendLine();
contents.AppendLine(fileData);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "key"));
contents.AppendLine();
contents.AppendLine(tpkey);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "consumer_token"));
contents.AppendLine();
contents.AppendLine(contoken);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "consumer_secret"));
contents.AppendLine();
contents.AppendLine(consecret);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "oauth_token"));
contents.AppendLine();
contents.AppendLine(usrtoken);
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "oauth_secret"));
contents.AppendLine();
contents.AppendLine(usrsecret);
if (!String.IsNullOrEmpty(tweetMessage))
{
contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "message"));
contents.AppendLine();
contents.AppendLine(tweetMessage);
}
contents.AppendLine(footer);
byte[] bytes = Encoding.GetEncoding(encoding).GetBytes(contents.ToString());
request.ContentLength = bytes.Length;
string mediaurl = "";
try
{
using (Stream requestStream = request.GetRequestStream()) // this is where the bug is due to not being able to seek.
{
requestStream.Write(bytes, 0, bytes.Length); // No problem the image is posted and tweet is posted
requestStream.Close();
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) // here I can't get the response
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string result = reader.ReadToEnd();
XDocument doc = XDocument.Parse(result); // this shows no root elements and fails here
XElement rsp = doc.Element("rsp");
string status = rsp.Attribute(XName.Get("status")) != null ? rsp.Attribute(XName.Get("status")).Value : rsp.Attribute(XName.Get("stat")).Value;
mediaurl = rsp.Element("mediaurl").Value;
return mediaurl;
}
}
}
}
catch (Exception ex)
{
ex.ToString();
}
return mediaurl;
}
}