每周源代码22- Digg, Flickr, Facebook, YouTube, Twitter, Live 服务,Google和Web 2.0 APIs 的C#,VB .NET库


[原文发表地址] The Weekly Source Code 22 – C# and VB .NET Libraries to Digg, Flickr, Facebook, YouTube, Twitter, Live Services, Google and other Web 2.0 APIs

[原文发表时间] 2008-03-26 04:02

有人最近给我发电子邮件说,在.NET中找不到足够多的范例来学习最新激增的“Web 2.0 APIs”。所以我琢磨着要列一张总表,一起看一些源码。我认为一个好的API封装包通常是不错的,但是由于这些API过于透明和基本,而且我们已经有LINQ to XML了,所以必要性不大。但我深知,当遇到”API”这个词时,还是会下意识的想到一个封装包。
需要提到的一点是,99.9%的API会调用
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
它们利用结果字符串在幕后工作。有些隐藏URL创建,有些使用XmlDocuments,有些使用XmlSerialization。如果您使用网络上的随便一个什么API, 那么就不要期望太高。你能看到不同的人对于他们心目中应该如何调用API的不同看法。有些人更喜欢速战速决,有些人则想得更透彻。
我会尽力比照它们之间的差距,但我希望你们记住,我们谈论的是摆布尖括号,而非其它的。你完全可以自己做。
所以,亲爱的读者,我现在向你们展示The Weekly Source Code.”一系列帖子中的第(22)个。
Digg
Digg(掘客)是一个由社区投票选出并有评论控制的汇聚大量新闻的站点 。它们的APIREST,并有XMLJSON接口。
DiggApiNETDigg API的一个.NET封装。它没有发布,所以你得拿它的源代码来用。最后一次更新是在2007年5月。还有一个在CodeProject中,名字比较“有创意”,叫digg API.NET
让我们来谈谈它的设计理念,然后看一下第一个库。这是从代码中抽选出来的一些代码段。该API构建了URL,并将访问结果加载到XmlDocument里,停顿片刻然后通过SelectNodes将值存入Digg特定的对象里。这些对象知道System.Xml的存在。
 1: private const string get_popular = "http://services.digg.com/stories/popular/comments/{0}"; 

 2:  

 3: public DiggComments GetPopular()

 4: { 

 5: return GetPopular(new Hashtable());

 6: }

 7: public DiggComments GetPopular(Hashtable args)

 8: { 

 9: string uri = String.Format(get_popular, HttpBuildUrl(args)); 

 10: return new DiggComments(Request(uri));

 11: }

 12: public DiggComments(XmlDocument xml_doc) : base(xml_doc, "events")

 13: { 

 14: _comments = new List<diggcomment>(); 

 15: if (xml_doc.SelectSingleNode("events") == null 

 16: || xml_doc.SelectSingleNode("events").SelectNodes("comment") == null) {

 17: throw new DiggApiException("XML response appears to be malformed, or contains unexpected data."); 

 18: }

 19: foreach (XmlNode node in xml_doc.SelectSingleNode("events").SelectNodes("comment")) {

 20: _comments.Add(new DiggComment(node)); 

 21: }

 22: }</diggcomment>

虽然这不算是完全“简洁”的方法,但却非常直观。使用SelectSingleNode和SelectNodes并不算太快,但我们关注的只是一小块数据,可能都低于100k.我可能会用XmlReader和XmlSerializer来处理,保不住还可能会用LINQ to XML. 我会创建一个服务(Service)来处理此协议,并让这些对象管的事情再少一些。
Facebook
Facebook有一个非常复杂和深入的API,并在.NET上有很多的支持。Nikhil对其进行了很好的诠释。你可以使用免费的Express Visual Studio版本来为Facebook做开发
下面有很多可用的:
有详细说明Facebook.NET资源库和Clarity Consulting’s公司的Facebook开发工具包Jay LagorioVB.NET编写了一个不错的Facebook客户端库JD Conley已经发布了一个叫fbasync的Facebook资源库,其主要专注于异步实现
Nikhil的Facebook客户端API的构造非常好。为每个主要的Facebook服务都创建了单独服务,还为Facebook会话对象提供了上下文状态。请求被封装到FacebookRequest里,会提供了异步选项,这个想的非常周到。
这儿有个编辑过的(为简便起见)WinForm范例,可以允许您设置您的Facebook状态。我喜欢IsPermissionGranted调用,在有很多权限的情况下,这个方法非常简洁,聪明。
 1: public partial class StatusForm : Form { 

 2: 

 3: private const string _apiKey = "[Your API Key]"; 

 4: private const string _secret = "[Your Secret]"; 

 5: 

 6: private FacebookService _fbService; 

 7: private bool _loggingIn; 

 8: 

 9: private void LoadStatus() { 

 10: _nameLabel.Text = "Loading..."; 

 11: 

 12: User user = _fbService.Users.GetUser(null, "name,status"); 

 13: if (user != null) { 

 14: _nameLabel.Text = user.Name; 

 15: 

 16: _statusTextBox.Text = user.Status.Message; 

 17: _dateLabel.Text = user.Status.UpdateDate.ToLocalTime().ToString("g"); 

 18: } 

 19: 

 20: bool canSetStatus = _fbService.Permissions.IsPermissionGranted(Permission.SetStatus); 

 21: _permissionsLink.Visible = !canSetStatus; 

 22: _updateButton.Enabled = canSetStatus; 

 23: _statusTextBox.ReadOnly = !canSetStatus; 

 24: } 

 25: 

 26: protected override void OnActivated(EventArgs e) { 

 27: base.OnActivated(e); 

 28: 

 29: if ((_fbService == null) && (_loggingIn == false)) { 

 30: _loggingIn = true; 

 31: 

 32: try { 

 33: FacebookClientSession fbSession = new FacebookClientSession(_apiKey, _secret); 

 34: if (fbSession.Initialize(this)) { 

 35: _fbService = new FacebookService(fbSession); 

 36: LoadStatus(); 

 37: } 

 38: } 

 39: finally { 

 40: _loggingIn = false; 

 41: } 

 42: } 

 43: } 

 44: 

 45: private void OnUpdateButtonClick(object sender, EventArgs e) { 

 46: string text = _statusTextBox.Text.Trim(); 

 47: 

 48: _fbService.Users.SetStatus(text, /* includesVerb */ true); 

 49: LoadStatus(); 

 50: } 

 51: }

 52: }

有趣的是,Facebook的API还包括了自带的JsonReader和JsonWriter,而不是使用新的JsonSerializer,大概是因为lib是一年前写的缘故吧。
Windows Live服务
http://dev.live.com/有一大堆信息和带有源码的完整的示例应用程序,以及一个Live SDK 互动网站。例如,Live Contacts API,不幸的是,在通讯录(Contacts)的API却找不到封装过尖括号(XML)的.NET范例,所以你可以按照你喜欢的方式解析。
Alpha SDK中提供的对象从一开始就集中在安全性和权限上。例如,在我以编程方式访问我的通讯录(Contacts)之前,我必须显示的允许访问,并选择一个允许访问的时间段。安全起见,我设定的安全访问时间是一天。
一旦你要检索一些数据,这是非常简单的事情,诸如https://cumulus.services.live.com/wlddemo@hotmail.com/LiveContacts这样的请求,会带给你:
 1: <LiveContacts> 

 2: <Owner> 

 3: <FirstName/> 

 4: <LastName/> 

 5: <WindowsLiveID/> 

 6: </Owner> 

 7: <Contacts> 

 8: <Contact> 

 9: <ID>{ContactID}</ID> 

 10: <WindowsLiveID>{Passport Member Name}</WindowsLiveID> 

 11: <Comment>comment here</Comment> 

 12: <Profiles/> 

 13: <Emails/> 

 14: <Phones/> 

 15: <Locations/> 

 16: </Contact> 

 17: </Contacts>

 18: </LiveContacts>

Live Search API 用SOAP协议,并且已经有了六种语言的范例, 包括C#, VB, Ruby, PHP, Python, and Java.

YouTube
YouTube有两个不同版本的API但原来的/旧版本已正式被弃用。因为它们已加入了Google,所以Youtube上的API全部都是Gdata风格的取代了原来的REST/XML-RPC API
有一个.NET库可以与GData XML格式交互,并可以非常简单的用C#来查询YouTube。你甚至可以像这位先生一样以编程的方式上传视频到YouTube.
这位朋友避开了GData的uber库,使用StringBuilder来构建GData有效载荷,这也行哦。:)
 1: private string GetHeader(string title, string description, Catagory catagory, 

 2: string keywords, string videoFileName)

 3: { 

 4: StringBuilder xml = new StringBuilder(); 

 5: xml.Append(boundary + lineTerm + "Content-Type: application/atom+xml; charset=UTF-8" + lineTerm + lineTerm); 

 6: xml.Append("<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" "); 

 7: xml.Append("xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\">"); 

 8: xml.AppendFormat("<media:group><media:title type=\"plain\">{0}</media:title>", title); 

 9: xml.AppendFormat("<media:description type=\"plain\">{0}</media:description>", description); 

 10: xml.AppendFormat("<media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">{0}</media:category>", catagory); 

 11: xml.AppendFormat("<media:keywords>{0}</media:keywords>", keywords); 

 12: xml.Append("</media:group></entry>" + lineTerm); 

 13: xml.Append(boundary + lineTerm + "Content-Type: video/*" + lineTerm + "Content-Transfer-Encoding: binary" + lineTerm + lineTerm); 

 14: return xml.ToString();

 15: }

GData
GData是谷歌通过XML 和HTTP传输数据的标准协议Blogger, Google Calendar, Notebook, Spreadsheets, Documents, Picassa等都有GData端点。下面是从它们的网站上截下来的:

NET开发人员指南是为特定数据API而制定的。你可以在每个数据API的页面上找到

GData C# 客户端是由Google编写的,所以我对他们的代码很感兴趣,因为他们的面试过程富有传奇色彩。我猜他们个个都是17岁的博士。该代码是极其面向对象的,包含有10个文件夹之多的165个文件(还不包括单元测试和项目上的东西)。注释也非常好,但有趣的是,该注释并不是大多数MSFT(微软)程序员使用的标准XML注释,而是一种我不熟悉的另外的格式。

所有的API都很相似。这儿有个GData查询日期范围内的日历上事件的范例。

 1: static void DateRangeQuery(CalendarService service, DateTime startTime, DateTime endTime)

 2: { 

 3: EventQuery myQuery = new EventQuery(feedUri); 

 4: myQuery.StartTime = startTime; 

 5: myQuery.EndTime = endTime; 

 6: 

 7: EventFeed myResultsFeed = service.Query(myQuery) as EventFeed; 

 8: 

 9: Console.WriteLine("Matching events from {0} to {1}:", 

 10: startTime.ToShortDateString(), 

 11: endTime.ToShortDateString()); 

 12: Console.WriteLine(); 

 13: for (int i = 0; i < myResultsFeed.Entries.Count; i++) 

 14: { 

 15: Console.WriteLine(myResultsFeed.Entries[i].Title.Text); 

 16: } 

 17: Console.WriteLine();

 18: }

下面是用Picassa从一个特定的用户上下载所有照片的示例。GData里的所有东西都是一个”AtomEntry” ,而且有很多扩展项。您可以处理GData类型或使用特定的子类,比如PhotoQuery,或其他什么方法,来使事情变得更简单。

 1: private static void DownAlbum(string UserN, string AlbumN)

 2: { 

 3: string fileName; 

 4: Uri uriPath; 

 5: WebClient HttpClient = new WebClient(); 

 6: // Three important elements of PicasaWeb API are 

 7: // PhotoQuery, PicasaService and PicasaFeed 

 8: PhotoQuery query = new PhotoQuery(); 

 9: query.Uri = new Uri(PhotoQuery.CreatePicasaUri(UserN, AlbumN)); 

 10: PicasaService service = new PicasaService("Sams PicasaWeb Explorer"); 

 11: PicasaFeed feed = (PicasaFeed)service.Query(query); 

 12: 

 13: Directory.SetCurrentDirectory("c:\\"); 

 14: foreach (AtomEntry aentry in feed.Entries) 

 15: { 

 16: uriPath = new Uri(aentry.Content.Src.ToString()); 

 17: fileName = uriPic.LocalPath.Substring(uriPath.LocalPath.LastIndexOf('/')+1); 

 18: try { 

 19: Console.WriteLine("Downloading: " + fileName); 

 20: HttpClient.DownloadFile(aentry.Content.Src.ToString(), fileName); 

 21: Console.WriteLine("Download Complete"); 

 22: } 

 23: catch (WebException we) 

 24: { Console.WriteLine(we.Message); } 

 25: }

 26: }

当然了如果你喜欢的话你也可以使用标准的Systeml.Xml API。

GData扩展了Atom Pub协议。Atom Pub是被Astoria(ADO.NET数据扩展)使用的一种协议,而Astoria基本上可以通过”LINQ to REST” 来访问。”

Flickr
Flickr有一个很好的API,并且WackyLabsy有一个用C#编写的针对FlickrNET API库的CodePlex项目。这也被证实了可以在Compact Framework,Mono以及.NET 1.1以上的版本上使用。在该库上有一篇很好的Coding4Fun文章
 1: PhotosSearchOptions options = new PhotosSearchOptions();

 2: options.Tags = "blue,sky";

 3: options.Extras |= PhotoSearchExtras.DateTaken | PhotoSearchExtras.OriginalFormat;

 4: Photos photos = flickr.PhotosSearch(options);

该API非常易用。例如,这个可以搜索带有蓝色和天空标签的图片,并且确保它返回DateTaken和OriginalFormat属性。
PhotosSearch()方法带有几十个包含日期范围、分页和其他选项的重载。所有工作都是让GetResponse()通过GetResponseCache()来实现的。URL都是在一个方法中被构建的,而响应是通过XmlSerializer进行获取数据并反序列化的。该API是最接近于我做的方式的。非常务实,并且尽可能多的使用了底层库,这个并不是真正的可扩展或过度的面向对象,但它能干净利落地完成任务。
由于Flickr是数据密集型的,该库也包括了一个线程安全的PersistentCache用来存储所有的数据。我可能会用System.Web.Cache,因为它能存在于任何应用程序中,甚至可以在ASP.NET之外。然而,该缓存是持久化的,可以将庞大的数据块保存到可配置的位置。我觉得,这其实是个非常有用的类,可以考虑在这个lib之外使用。它将所有东西存储在超级“穷光蛋”数据库上,这基本上是一个序列化的blob哈希表,ala (gasp) OLE结构的存储结构

WordPress和基于XML – RPC的博客

大多数博客都使用Blogger或MetaWeblog API,因为他们很容易通过.NET来调用。包括MSN SpacesDasBlogSubText等等。关于如何用C# 或 VB访问XML-RPC,在MSDN上有很多深入研究的范例

当你写帖子时,Windows Live WriterBlogJet会使用这些API来与博客进行交互,所以我现在用的就是.NET和XML-RPC 😉

这儿有个用VB.NET编写的使用了很棒的 XML-RPC.NET库的的一个非常简单的示例。这里有一个更完整的范例这是一个小型的博客客户端

DasBlog使用这个库做成了一个XML-RPC服务器。

在此示例中,”IWP”类型派生自XmlRpcProxy,并使用了分类结构。该库还负责处理所有的反序列化映射,比方说调用XML-RPC ,,感觉像是使用WebService,尽管XML – RPC是SOAP的前身,但并不是你正在使用的SOAP。

 1: Dim proxy As IWP = XmlRpcProxyGen.Create(Of IWP)()

 2: Dim args() As String = {“http://myblog.blogstogo.com”, _ 

 3: “username”, “password”}

 4: Dim categories() As categorycategories = proxy.getCategories(args)

你也可以使用WCF来与XML-RPC进行交互

Twitter
以前我也提到过Twitter。它有一个Twitter API,这至少是个比其网站更重要的重量级的东东。有一大堆的源代码,可以与Twitter进行交互。
去年,Alan Le在博客上写到了要创建一个围绕Twitter的API库的大胆设想Witty是面向Twitter的活跃开发中的WPF C#应用程序你可以浏览源网址,参见他们的简单的TwitterLib
TwitterNet.cs是它的核心部分,其使用XmlDocuments创建对象,并实现了这些代码,我叫它“左手/右手”代码。那是因为你左边有一个对象,右边有其他的object/bag/pileOdata,然后你会用很多代码行来不停的去左侧,右侧,左侧,右侧。
(裁剪过)的示例如下:
 1: public UserCollection GetFriends(int userId) 

 2: { 

 3: UserCollection users = new UserCollection(); 

 4:  

 5: // Twitter expects https://twitter.com/statuses/friends/12345.xml 

 6: string requestURL = FriendsUrl + "/" + userId + Format; 

 7:  

 8: int friendsCount = 0; 

 9: 

 10: // Since the API docs state "Returns up to 100 of the authenticating user's friends", we need 

 11: // to use the page param and to fetch ALL of the users friends. We can find out how many pages 

 12: // we need by dividing the # of friends by 100 and rounding any remainder up. 

 13: // merging the responses from each request may be tricky. 

 14: if (currentLoggedInUser != null && currentLoggedInUser.Id == userId) 

 15: { 

 16: friendsCount = CurrentlyLoggedInUser.FollowingCount; 

 17: } 

 18: else 

 19: { 

 20: // need to make an extra call to twitter 

 21: User user = GetUser(userId); 

 22: friendsCount = user.FollowingCount; 

 23: } 

 24: 

 25: int numberOfPagesToFetch = (friendsCount / 100) + 1; 

 26:  

 27: string pageRequestUrl = requestURL; 

 28: 

 29: for (int count = 1; count <= numberOfPagesToFetch; count++) 

 30: { 

 31: pageRequestUrl = requestURL + "?page=" + count; 

 32: HttpWebRequest request = WebRequest.Create(pageRequestUrl) as HttpWebRequest; 

 33: request.Credentials = new NetworkCredential(username, password); 

 34: 

 35: try 

 36: { 

 37: using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) 

 38: { 

 39: StreamReader reader = new StreamReader(response.GetResponseStream()); 

 40: XmlDocument doc = new XmlDocument(); 

 41: doc.Load(reader); 

 42: XmlNodeList nodes = doc.SelectNodes("/users/user"); 

 43: 

 44: foreach (XmlNode node in nodes) 

 45: { 

 46: User user = new User(); 

 47: user.Id = int.Parse(node.SelectSingleNode("id").InnerText); 

 48: user.Name = node.SelectSingleNode("name").InnerText; 

 49: user.ScreenName = node.SelectSingleNode("screen_name").InnerText; 

 50: user.ImageUrl = node.SelectSingleNode("profile_image_url").InnerText; 

 51: user.SiteUrl = node.SelectSingleNode("url").InnerText; 

 52: user.Location = node.SelectSingleNode("location").InnerText; 

 53: user.Description = node.SelectSingleNode("description").InnerText; 

 54:  

 55: users.Add(user); 

 56: } 

 57: } 

 58: } 

 59: catch (WebException webExcp) 

 60: { 

 61: // SNIPPED BY SCOTT 

 62: } 

 63: } 

 64: return users; 

 65: }

到目前为止,我想使用的Web 2.0应用程序都有了相应的.NET库。我甚至在去年就匆匆的给Wesabe建了一个.NET客户端,后来又用IronRuby写了一个

希望你们喜欢,另外代码的海洋里,我错过什么了呢?


Comments (1)

  1. Tad Zhai says:

    Cool, I'll keep it for reference.

Skip to main content