2010-12-13 13 views
3

OAuthを使用して、C#で書かれた.NETアプリからTwitPicに写真をアップロードしています。TwitPic + OAuthを使用して写真+ツイートをTwitterにアップロードする(.NET C#) - なぜツイートはありませんか?

oAuthのものはちょっと難しいです。私はそれを処理するために2ビットの.NETコードを見つけましたが、いずれにも満足していませんでした。 DotNetOpenAuthは、私が必要以上に重く感じられました。 (ちょうどoAuth署名とトークン要求をしたい)。 OAuthBase.csコードは私にとっては混乱していて、やさしく感じられませんでした。私はメソッドに6文字列のパラメータを渡さなければならなかった。もし何か不具合があったなら、私にはうんざりだ。

私はそれを自分自身で行うためにいくつかのコードを書いています。それはかなり小さく、うまくいくようです。それは "要求トークン"を取得するために動作します。これは、権限Webページをポップし、 "アクセストークン"を取得するために動作します。 TwitPicに写真をアップロードすることもできます。私は戻って、アップロードから取得

POST http://api.twitpic.com/2/upload.json HTTP/1.1 
Content-Type: multipart/form-data; boundary=48cb9a6d-1f1d-432d-b6e3-307e32e8228a 
X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json 
X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/", 
    oauth_consumer_key="Dv1er93yKzEMn74hZfPmJA", 
    oauth_nonce="51fi305k", 
    oauth_signature="4oWcmZcd%2F%2F81JslJ70xFXFm8%2BQs%3D", 
    oauth_signature_method="HMAC-SHA1", 
    oauth_timestamp="1292277715", 
    oauth_token="59152613-z8EP4GoYS1Mgo3E29JfIqBnyTRlruAJs8Bkvs3q0T", 
    oauth_version="1.0" 
Host: api.twitpic.com 
Content-Length: 14605 
Expect: 100-continue 
Connection: Keep-Alive 

--48cb9a6d-1f1d-432d-b6e3-307e32e8228a 
Content-Disposition: file; name="media"; filename="CropperCapture[10].jpg" 
Content-Type: image/jpeg 
.... 
--48cb9a6d-1f1d-432d-b6e3-307e32e8228a 
Content-Disposition: form-data; name="key" 

twitpic-api-key-here 
--48cb9a6d-1f1d-432d-b6e3-307e32e8228a 
Content-Disposition: form-data; name="message" 

uploaded from Yappy. (at 12/13/2010 5:01:55 PM) 
--48cb9a6d-1f1d-432d-b6e3-307e32e8228a-- 

JSONはこのようなものです::

{"id":"3f0jeiw5", 
"text":"uploaded from Yappy. (at 12\/13\/2010 5:01:55 PM)", 
"url":"http:\\/twitpic.com\/3f0jeiw5", 
"width":257, 
"height":184, 
"size":14156, 
"type":"jpg", 
"timestamp":"Mon, 13 Dec 2010 22:02:06 +0000", 
"user":{ 
    "id":54591561,"screen_name":"bfavre"} 
} 

すべてのHTTP応答はupload HTTP messageはこのようになります200または201

として戻ってきます

しかし、問題は、Twitpicに画像をアップロードした後、その画像がTwitPicで利用可能だが、関連するメッセージがTwitterに表示されないということだ。

何がありますか?

a random blog post TwitPic + oAuthを使用すると、別のHTTPトランザクションでTwitterに直接Twitterのメッセージを投稿する必要があります。ハァッ? oAuthのメールの目的は、消費者が私のために何かをすることを許すことだと思っていました - TwitPicに私のためにツイートを投稿できるようにすること。

ヒント


EDIT
私はもう少しここで学びました。 This blog postから2010年5月には、X-Auth-Service-Providerの値をhttps://api.twitter.com/1/account/verify_credentials.jsonにすると、twitpicが自分のリクエストを受け取ったときに "verify_credentials.json"を "twitter.com"で呼び出すように指示しています。本当に自分の資格情報を確認しているだけの場合、これはなぜTweetが投稿されないのかを説明します。

投稿はまた、それを交換してそれをhttps://api.twitter.com/1/status/update.jsonと置き換えると、はTwitPic経由の委任をTwitterで更新できるはずだと示唆しています。しかし、それは先見的なポストです。この能力を得るにはTwitterの仕事が必要だと言います。

まだこれを行うHTTPメッセージの例は見つかりませんでした。誰でも?


UPDATE
https://api.twitter.com/1/status/update.jsonにURLを検証し、署名のためのPOSTを使用して変換した後、私は401レスポンスコードを取得:

{"errors": 
    [{"code":401, 
    "message":"Could not authenticate you (header rejected by twitter)."}] 
} 

これは基本的にhere, in the twitter dev forumを説明したのと同じ問題です。そのスレッドの最後の提案は、署名計算アルゴリズムが間違っていたことですが、私のsigアルゴリズムは他のすべての要求と連携しているので、間違っていると思います。

答えて

1

私は最終的な答えはわかりませんが、Raffi's blog post of May 2010に "Real Soon Now"と記載されていた変更は、何らかの理由で実際には行われていないと思います。

実際、OAuthを使用すると、となり、TwitPicとTwitterに別々に投稿する必要があります。

Twitterでこれを行うのは難しくありません。 statuses/update.xml URLでPOSTを実行するだけです。

private void Tweet(string message) 
{ 
    var twitterUpdateUrlBase = "http://api.twitter.com/1/statuses/update.xml?status="; 
    var url = twitterUpdateUrlBase + UrlEncode(message); 

    var authzHeader = oauth.GenerateAuthzHeader(url, "POST"); 

    var request = (HttpWebRequest)WebRequest.Create(url); 
    request.Method = "POST"; 
    request.PreAuthenticate = true; 
    request.AllowWriteStreamBuffering = true; 
    request.Headers.Add("Authorization", authzHeader); 

    using (var response = (HttpWebResponse)request.GetResponse()) 
    { 
     if (response.StatusCode != HttpStatusCode.OK) 
     MessageBox.Show("There's been a problem trying to tweet:" + 
         Environment.NewLine + 
         response.StatusDescription + 
         Environment.NewLine + 
         Environment.NewLine + 
         "You will have to tweet manually." + 
         Environment.NewLine); 
    } 
} 

このコードには2つのトリッキーな部分があります。最初はUrlEncode()呼び出しです。 OAuthは、urlencodingで大文字を使用する必要があることを指定します。組み込みの.NETルーチンは小文字を使用します。だから、大事にしてください。

第2の難しい部分は、OAuth認証ヘッダーを取得していることです。 OAuthライブラリパッケージを使用する場合は、かなりシンプルでなければなりません。簡単なものをお望みの方には、get one here: OAuth.csです。 (OAuthManagerをdownloaDにしてください)

+0

FYI - 私はあなたのシンプルなOAuthライブラリが好きです。私は拡張文字を扱うための迅速な修正を行い、ここに投稿しました:http://cropperplugins.codeplex.com/discussions/249415 – russau

+0

あなたの変更はOAuthライブラリにあります。また、現在誰でもダウンロードできるDLLがあります。 – Cheeso

1

oAuth統合を生成するためにTwitpic APIを使用しています。Twitpicから送信された画像とTwitterのコメントがTwitpicから送信されることがわかりました。これは私たちのEplixo(http://eplixo.com/m/)ビデオチャットとツイッタークライアントのtwitterユーザーアカウントに画像を投稿します

しかし、私は応答を得るように見えません。今私はそれを投稿してアップロードすることで暮らすことができますが、アプリケーションの他の部分のレスポンスデータを取得する方法を理解することは役に立ちます。

これは私が持っているものです。これはTwipli APIラッパーのバリエーションです

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

} 
関連する問題