豆瓣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