豆瓣api經過OAuth容許第三方應用訪問用戶數據,因此OAuth認證就是咱們整個project的基礎了。web
OAuth認證聽起來挺神祕,其實挺簡單的。windows
如今的大型網站的開放平臺的認證幾乎都是採用OAuth,好比facebook,twitter,新浪微博等。api
豆瓣的api有對於OAuth認證的專門說明:http://www.douban.com/service/apidoc/auth服務器
在你使用OAuth認證以前,先仔細讀一讀文檔很是有必要,由於中間過程出現一點誤差,你就不能被認證成功,因此仔細閱讀官方文檔是重中之重:http://oauth.net/documentation/spec/網絡
若是你的英文不夠給力的話,能夠看看這篇中文的介紹,說的很清楚:http://www.supidea.com/post/oauth.aspxapp
google OAuth項目已經提供了OAuth的各類語言的庫:http://code.google.com/p/oauth/異步
咱們正式使用了google OAuth中的C#庫: http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cside
由於OAuth已經成爲了第三方開發者使用豆瓣api的一大障礙,豆瓣曾經專門舉辦了一次活動來說解如何經過OAuth使用豆瓣api:http://www.douban.com/online/10012959/svn
此次活動的源碼在google code上能夠找到:http://code.google.com/p/douban-oauth-sample/,咱們正式參考了http://code.google.com/p/douban-oauth-sample/source/browse/trunk/csharp/DoubanOAuthBasicSample/DoubanOAuthBasicSample/Program.cs這個文件,對咱們的幫助很大,省去了不少摸索的時間函數
做爲命令行程序咱們已經測試成功了,可是當移植到windows phone上以後就出現了問題
問題的關鍵在於silverlight版的網絡方面的api和C#的不一樣,silverlight的api更少,這就致使了上面的庫的一些網絡訪問要本身改寫
仔細閱讀httpwebrequest的文檔後,咱們發現,要進行一個網絡請求,至少要三個函數,由於須要使用兩次異步請求(BeginGetRequestStream,BeginGetResponse)
由於咱們的豆瓣app幾乎每一個動做都要對豆瓣服務器進行請求,若是每一個請求都須要寫三個函數,而且還要增長認證信息的話,實在是太麻煩,代碼會變得又臭又長
這時候DRY(don’t repeat yourself)就顯得尤其重要了
做爲pm,我決定把網絡訪問這一塊封裝好,給你們提供統一的,簡單好用的藉口。
我本準備本身把那兩個異步請求封裝起來,後來發現已經有現成的庫可用,並且很好很強大。
這個庫就是restsharp:http://restsharp.org/
並且restsharp還提供了windows phone對應的dll,非常方便,原來的三個函數如今只須要一個函數幾行就能夠搞定
對於不少請求,豆瓣都要求有認證才能夠訪問,根據豆瓣的文檔「進行POST、PUT、DELETE請求時,豆瓣暫時不支持使用在url中或者post form中傳遞OAuth參數。所以你只能選擇在header中傳遞OAuth參數」,看來咱們只能把oauth加到http header中了。
我部分我統一封裝了一下:
namespace AddOAuthHeader{
public class OAuthHeader{
string apiKey = "your api key";
string apiKeySecret = "your api key secret";
string accessToken;
string accessTokenSecret;
string uri;
string method;
OAuthBase oAuth = new OAuthBase();
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
public OAuthHeader(string uri, string method) {
this.uri = uri;
this.method = method;
}
public string getHeader(){
string nonce = oAuth.GenerateNonce();
string timeStamp = oAuth.GenerateTimeStamp();
string normalizeUrl, normalizedRequestParameters;
//accessToken = settings["accessToken"].ToString();
//accessTokenSecret = settings["accessTokenSecret"].ToString();
accessToken = "ee7ead643e6ea1a1cb7c082cbb4be4e3";
accessTokenSecret = "545138430a2dcc9b";
string sig = oAuth.GenerateSignature(
new Uri(uri),
apiKey,
apiKeySecret,
accessToken,
accessTokenSecret,
method,
timeStamp,
nonce,
OAuthBase.SignatureTypes.HMACSHA1,
out normalizeUrl,
out normalizedRequestParameters);
sig = HttpUtility.UrlEncode(sig);
StringBuilder oauthHeader = new StringBuilder();
oauthHeader.AppendFormat("OAuth realm=\"\", oauth_consumer_key={0}, ", apiKey);
oauthHeader.AppendFormat("oauth_nonce={0}, ", nonce);
oauthHeader.AppendFormat("oauth_timestamp={0}, ", timeStamp);
oauthHeader.AppendFormat("oauth_signature_method={0}, ", "HMAC-SHA1");
oauthHeader.AppendFormat("oauth_version={0}, ", "1.0");
oauthHeader.AppendFormat("oauth_signature={0}, ", sig);
oauthHeader.AppendFormat("oauth_token={0}", accessToken);
return oauthHeader.ToString();
}
}
}
傳入一個url和一個方法(post or put or delete or get),我就給他返回一個oauth header,其餘同窗直接調用個人代碼就行了,並不須要關心認證問題
那具體該如何來進行一個網絡請求呢?
我寫了兩個例子,一個post的,一個get的。
向豆瓣傳數據,post:(我把說明都寫到了註釋中)
// "POST" 實例,以發一條狀態爲例
private void button1_Click(object sender, RoutedEventArgs e)
{
//首先都要先實例化一個OAuthHeader,傳入的參數爲url和網絡請求的方法(post or get or delete or put or something else)
OAuthHeader header = new OAuthHeader("http://api.douban.com/miniblog/saying", "POST");
//對於post,要傳給服務器一些數據,豆瓣api用xml來傳數據,就須要先build一個xml的string
StringBuilder requestBody = new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>");
requestBody.Append("<entry xmlns:ns0=\"http://www.w3.org/2005/Atom\" xmlns:db=\"http://www.douban.com/xmlns/\">");
requestBody.Append("<content>hello world</content>");
requestBody.Append("</entry>");
//下面兩行是每個網絡請求都須要的,即與api.douban.com創建一個鏈接
var client = new RestClient();
client.BaseUrl = "http://api.douban.com";
//下面這行的意思是產生一個請求,第一個參數是路徑名(不是完整的url),後面是Method.POST 或 Method.GET 或Method.PUT 或 Method.DELETE
var request = new RestRequest("/miniblog/saying", Method.POST);
//下面進行一些http頭的設置
//先設置request的format爲xml
request.RequestFormat = DataFormat.Xml;
request.AddHeader("Content-Type", "application/atom+xml");
//而後是把生成的authorization寫入http的header
request.AddHeader("Authorization", header.getHeader());
//最終把要上傳的數據寫入http請求中,注意要加上ParameterType.RequestBody
request.AddParameter("application/atom+xml", requestBody.ToString(), ParameterType.RequestBody);
//最後就是進行異步網絡請求了,而且將傳回的response的信息解析出來,呈如今頁面上
client.ExecuteAsync(request, (response) =>
{
var resource = response.Content;
Debug.WriteLine(resource);
});
}
//GET實例,以獲取好友列表爲例,get比較簡單,不須要傳入數據
private void button3_Click(object sender, RoutedEventArgs e)
{
//同上
OAuthHeader header = new OAuthHeader("http://api.douban.com/people/34788764/contacts?start-index=1&max-results=50", "GET");
var client = new RestClient();
client.BaseUrl = "http://api.douban.com";
//注意,這裏生成request的時候,不要把?後面的parameter加上,parameter要在後面的request.AddParameter處實現
var request = new RestRequest("/people/34788764/contacts", Method.GET);
//加上認證頭
request.AddHeader("Authorization", header.getHeader());
//加上參數
request.AddParameter("start-index", "1");
request.AddParameter("max-results", "50");
client.ExecuteAsync(request, (response) =>
{
var resource = response.Content;
Debug.WriteLine(resource);
textBlock1.Text = resource;
});
}
這樣就能夠大大簡化網絡請求,真正作到了don’t repeat yourself