2010-12-13 1 views
3

OAuth을 사용하여 C#으로 작성된 .NET 응용 프로그램에서 사진을 TwitPic에 업로드하고 있습니다.TwitPic + OAuth를 사용하여 사진 + 트윗을 Twitter에 업로드 (.NET C#) - 왜 트윗이 없습니까?

oAuth 물건은 약간 까다 롭습니다. .NET 코드를 처리하기 위해 두 비트의 .NET 코드를 발견했지만 만족스럽지 않았습니다. DotNetOpenAuth은 내가 필요로하는 것보다 훨씬 무거워 보였다. (그냥 oAuth 서명과 토큰 요청을하고 싶다). OAuthBase.cs 코드는 나에게 혼란스럽고 우아하지 않았습니다. 메서드에 6 개의 문자열 매개 변수를 전달해야하며 순서가 잘못 되었다면 저에게 화가있을 수 있습니다.

그래서 저는 약간의 코드를 작성하여 매우 작아서 작동하는 것으로 보입니다. 그것은 "요청 토큰"을 획득하기 위해 작동합니다. 그것은 허가 웹 페이지를 띄우고 "액세스 토큰"을 얻기 위해 작동합니다. TwitPic에 사진을 업로드하는 기능도 있습니다.

upload HTTP message은 다음과 같습니다 (200) 또는 (201)

모든 HTTP 응답은 돌아 오지 :

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

하지만 문제는 Twitpic에 이미지를 업로드 한 후 TwitPic에서 이미지를 사용할 수 있지만 관련 메시지가 Twitter에 표시되지 않는다는 것입니다.

무엇을 제공합니까?

a random blog post 나는 TwitPic + oAuth를 사용하여 트위터에 별도의 HTTP 트랜잭션으로 트윗 메시지를 게시해야 함을 읽었습니다. 응? oAuth의 메일 목적은 소비자가 나를 대신하여 일할 수있게하는 것이라고 생각했습니다. TwitPic에 트윗을 올릴 수 있도록 허용하는 것입니다.

힌트가 있습니까?


내가 여기에 조금 더 배우고
편집 할 수 있습니다. This blog post에서 2010 년 5 월에 X-Auth-Service-Provider의 값을 https://api.twitter.com/1/account/verify_credentials.json으로 사용하면 twitpic이 내 요청을받을 때 "verify_credentials.json"을 twitter.com에서 호출하도록 알려줍니다. 정말로 내 자격 증명을 확인하는 중이라면 짹짹이 게시되지 않는 이유를 설명합니다.

게시물은 또한 스와핑 및 https://api.twitter.com/1/status/update.json로 대체하는 나를 대표단 TwitPic을 통해 트위터를 업데이트 할 수 있도록해야한다고 제안한다. 그러나이 기능을 사용하려면 Twitter의 작업이 필요하다고 전향적인 게시물입니다.

아직까지도이를 수행하는 예제 HTTP 메시지를 찾지 못했습니다. 누군가? here, in the twitter dev forum 바와 같이

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

이 기본적으로 같은 문제가 다음 서명 https://api.twitter.com/1/status/update.json로 확인 URL을 변환 POST 사용 후


UPDATE
는, I는 401 응답 코드를 얻는다.그 스레드의 끝에 제안은 서명 계산 알고리즘이 잘못되었다는 것이지만, 내 sig 알고리즘이 다른 모든 요청과 함께 작동하기 때문에 잘못된 것이라고 생각합니다.

답변

1

최종 답변을 모르겠지만 어떤 이유에서든 Raffi's blog post of May 2010에 "Real Soon Now"로 변경된 내용이 실제로 작성되지 않았다고 생각합니다.

실제로 OAuth를 사용하면 과 같이 TwitPic과 Twitter에 별도로 게시해야합니다.

하지만 트위터에서는 그렇게하기가 어렵지 않습니다. statuses/update.xml URL에서 POST를 수행하면됩니다. 먼저이를 UrlEncode() 호출입니다 :

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

그 코드에 두 까다로운 부분이 있습니다. OAuth는 urlencoding이 대문자를 사용해야 함을 지정합니다. 기본 제공 .NET 루틴은 소문자를 사용합니다. 그래서 대문자로해야합니다.

두 번째 까다로운 부분은 OAuth 인증 헤더를 얻는 것입니다. OAuth 라이브러리 패키지를 사용하는 경우 매우 간단해야합니다. 간단한 것을 원한다면 get one here: OAuth.cs을 사용할 수 있습니다. (OAuthManager 다운로드 downloaD)

+0

참고 - 저는 간단한 OAuth 라이브러리를 좋아합니다. 확장 문자를 처리하기위한 빠른 수정을하고 여기에 게시했습니다. http://cropperplugins.codeplex.com/discussions/249415 – russau

+0

감사합니다. 이제 변경 사항이 OAuth 라이브러리에 있습니다. 또한, 이제 누구나 다운로드 할 수있는 DLL이 있습니다. – Cheeso

1

oAuth 통합을 생성하기 위해 Twitpic API를 사용하여 작업 한 결과 이미지를 게시 할 수 있고 Twitpic에서 보낸 Twitter 주석을 찾을 수 있습니다. 이것은 Eplixo (http://eplixo.com/m/) 화상 채팅 및 트위터 클라이언트의 트위터 사용자 계정에 이미지를 게시합니다.

그러나 응답을 얻지 못하는 것 같습니다. 이제는 게시 및 업로드를 통해 살 수 있지만 응용 프로그램의 다른 부분에 대한 응답 데이터를 얻는 방법을 파악하는 것이 유용 할 것입니다.

다음은 내가 가지고있는 것입니다. 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; 
    } 

}