PageRenderTime 59ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Amptools/Public/labels/Flickr.aspx

https://github.com/pvencill/amptools
ASP.NET | 411 lines | 314 code | 97 blank | 0 comment | 13 complexity | 16febf6ab140b6f221d2f429fca1808a MD5 | raw file
  1. <%@ Page Title="amptools.net" Language="C#" MasterPageFile="~/App/Views/Layouts/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="System.Web.Mvc.ViewPage" %>
  2. <asp:Content ID="Content2" ContentPlaceHolderID="Head" runat="server">
  3. <link href='/Content/default/css/syntax-highlighter.css' rel="stylesheet" type="text/css" />
  4. <link rel="alternate" type="application/rss+xml" title="amptools.net - RSS" href="http://feeds.feedburner.com/amptoolsnet" />
  5. <link rel="service.post" type="application/atom+xml" title="amptools.net - Atom" href="http://www.blogger.com/feeds/7043853799247804655/posts/default" />
  6. <link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://www.blogger.com/rsd.g?blogID=7043853799247804655" />
  7. <style type="text/css">
  8. @import url("http://www.blogger.com/css/blog_controls.css");
  9. @import url("http://www.blogger.com/dyn-css/authorization.css?targetBlogID=7043853799247804655");
  10. </style>
  11. <script type="text/javascript" src="http://www.blogger.com/js/backlink.js"></script>
  12. <script type="text/javascript" src="http://www.blogger.com/js/backlink_control.js"></script>
  13. <script type="text/javascript">var BL_backlinkURL = "http://www.blogger.com/dyn-js/backlink_count.js";var BL_blogId = "7043853799247804655";</script>
  14. </asp:Content>
  15. <asp:Content ID="Content3" ContentPlaceHolderID="Javascript" runat="server">
  16. <script type="text/javascript" src="~/javascripts/prototype.js"></script>
  17. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shCore.js"></script>
  18. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushCSharp.js"></script>
  19. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushRuby.js"></script>
  20. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushJScript.js"></script>
  21. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushCss.js"></script>
  22. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushSql.js"></script>
  23. <script type="text/javascript" src="~/javascripts/syntax-highlighter/shBrushXml.js"></script>
  24. <script type="text/javascript">
  25. //<[CDATA[
  26. dp.SyntaxHighlighter.HighlightAll('code');
  27. //]]>
  28. </script>
  29. </asp:Content>
  30. <asp:Content ID="Content1" ContentPlaceHolderID="main" runat="server">
  31. <div class="left">
  32. <h2 class="silver">
  33. &quot;Working on the complexity that is always indirectly implied by simpilicity.&quot;
  34. </h2>
  35. <h2 class="blog-title"><a name="8164722880411458481"></a>
  36. Using WCF to access the Flickr JSON API
  37. <span class="blog-byline">
  38. by: michael herndon, at: 7/17/2008 06:40:00 AM
  39. </span>
  40. </h2>
  41. <div class="blog-content">
  42. <p>Even though there are quite a few opensource .Net libraries REST API out there, and a really impressive one for Flickr, they tend to never evolve or fork to use the newer framework technologies.&#160; I think its great that they support 1.0, 2.0, and mono, but why not fork and support WCF?&#160; I think part of the problem that .Net 3.5 use is not wide spread as it should be is not only information overload and bad naming for extension libraries, but also lack of opensource support to provide libraries and basis for current technology.&#160; </p> <p>Flickr tends to be a little more tricky to use when calling it than some other REST APIs. WCF is a cool technology, but needs to be massaged when using it with Flickr due to a couple of gotchas and not so obvious things about WCF. In order to use Flickr, you need to register for an api_key and a shared secret code which is used to create an MD5 hash. You also need to create that MD5 each time you call a method, using the url parameters in a certain way. </p> <p>There are also a few not so obvious factors about using the JSON part of Flickr. All of the .Net libraries I've seen so far, use XML. While C# is king of parsing&#160; XML, JSON tends to be more compact, which means less expense over the wire, though it might mean more time parsing once on the developers end point. So there are tradeoffs to using it. </p> <p>When I created the classes needed to use WCF to call Flickr, I have the actual &quot;DataContract&quot; object (DTO, Data Transfer Object), A Hash (Dictionary&lt;string, object&gt;) for adding the parameters to create the MD5 signature, A base class for creating the WCF proxy, a custom &quot;WebContentTypeMapper&quot;, The &quot;ServiceContract&quot; interface, the actual &quot;Client class&quot;, and a mixins class for creating the MD5. </p> <p>Here are some of the gotchas that I ran into while getting WCF to work with Flickr. </p> <p></p> <ol> <li>Flickr makes you create a md5 hash to send with every call for ALL parameters in alphabetical order using your &quot;Shared Secret&quot; Code as part of the md5.&#160;&#160; </li> <li>Flickr's Json response &quot;Content-Type&quot; header is sent not as &quot;application/json&quot; but as &quot;text/plain&quot; which equates to &quot;Raw&quot; in WCF lingo.&#160; </li> <li>The response object is wrapped and not obvious when it comes to json how the DataContract object should be formed.&#160; </li> <li>Flickr will wrap the json response in a javascript function unless you pass in the parameter &quot;nojsoncallback=1&quot; </li> </ol> <p>To get around number one, I created an extension method that takes a Hash (Dictionary&lt;string, object&gt;) and adds method that converts the parameters into a MD5 string. </p> <pre class="code csharp">namespace Amplify.Linq
  43. {
  44. using System;
  45. using System.Collections.Generic;
  46. using System.Linq;
  47. using System.Text;
  48. #if STANDALONE
  49. public class Hash : Dictionary&lt;string, object&gt;
  50. {
  51. }
  52. #endif
  53. }
  54. // different file
  55. namespace Amplify.Linq
  56. {
  57. using System;
  58. using System.Collections.Generic;
  59. using System.Linq;
  60. using System.Security.Cryptography;
  61. using System.Text;
  62. using Amplify.Linq;
  63. public static class Mixins
  64. {
  65. public static string ToMD5(this Hash obj, string secret)
  66. {
  67. var query = from item in obj
  68. orderby item.Key ascending
  69. select item.Key + item.Value.ToString();
  70. StringBuilder builder = new StringBuilder(secret, 2048);
  71. foreach (string item in query)
  72. builder.Append(item);
  73. MD5CryptoServiceProvider crypto = new MD5CryptoServiceProvider();
  74. byte[] bytes = Encoding.UTF8.GetBytes(builder.ToString());
  75. byte[] hashedBytes = crypto.ComputeHash(bytes, 0, bytes.Length);
  76. return BitConverter.ToString(hashedBytes).Replace(&quot;-&quot;, &quot;&quot;).ToLower();
  77. }
  78. }
  79. }</pre>
  80. <p>Well Gotcha number two, took a bit of research to figure it out. The error I got was that it was looking for Json or XML but could not do anything with &quot;Raw&quot;. So the solution is to create a custom binding with a custom WebContentTypeManager. </p>
  81. <pre class="code csharp">namespace Amplify.Flickr
  82. {
  83. using System.ServiceModel;
  84. using System.ServiceModel.Channels;
  85. using System.Runtime.Serialization;
  86. using System.ServiceModel.Web;
  87. public class JsonContentMapper : WebContentTypeMapper
  88. {
  89. public override WebContentFormat GetMessageFormatForContentType(string contentType)
  90. {
  91. return WebContentFormat.Json;
  92. }
  93. }
  94. }
  95. // different file
  96. namespace Amplify.Flickr
  97. {
  98. using System;
  99. using System.Collections.Generic;
  100. using System.Linq;
  101. using System.Text;
  102. using System.ServiceModel;
  103. using System.ServiceModel.Channels;
  104. using System.ServiceModel.Description;
  105. using System.ServiceModel.Web;
  106. using Amplify.Linq;
  107. public class FlickrClient&lt;T&gt;
  108. {
  109. protected string Secret { get; set; }
  110. protected string Key { get; set; }
  111. protected string Token { get; set; }
  112. protected string Url { get; set; }
  113. protected T Proxy { get; set; }
  114. public FlickrClient(string key, string secret)
  115. {
  116. this.Key = key;
  117. this.Secret = secret;
  118. this.Url = &quot;http://api.flickr.com/services/rest&quot;;
  119. this.Proxy = this.InitializeProxy();
  120. }
  121. public FlickrClient(string key, string secret, string token)
  122. :this(key, secret)
  123. {
  124. this.Token = token;
  125. }
  126. protected virtual T InitializeProxy()
  127. {
  128. // using custom wrapper
  129. CustomBinding binding = new CustomBinding(new WebHttpBinding());
  130. WebMessageEncodingBindingElement property = binding.Elements.Find&lt;WebMessageEncodingBindingElement&gt;();
  131. property.ContentTypeMapper = new JsonContentMapper();
  132. ChannelFactory&lt;T&gt; channel = new ChannelFactory&lt;T&gt;(
  133. binding, this.Url);
  134. channel.Endpoint.Behaviors.Add( new WebHttpBehavior());
  135. return channel.CreateChannel();
  136. }
  137. }
  138. }</pre>
  139. <p>The 3rd issue, to know that all objects are wrapped in a &quot;Response&quot; object. To create a DataContract for the getFrob method on flickr, it took looking at the json to see what it was returning. The object below is the basic form of the Json object that is returned, it also includes the properties in case an error object is returned. </p>
  140. <pre class="code csharp"> using System;
  141. using System.Collections.Generic;
  142. using System.Linq;
  143. using System.Text;
  144. using System.Runtime.Serialization;
  145. [DataContract]
  146. public class FrobResponse
  147. {
  148. [DataMember(Name = &quot;frob&quot;)]
  149. public JsonObject Frob { get; set; }
  150. [DataContract(Name = &quot;frob&quot;)]
  151. public class JsonObject
  152. {
  153. [DataMember(Name = &quot;_content&quot;)]
  154. public string Content { get; set; }
  155. }
  156. [DataMember(Name = &quot;stat&quot;)]
  157. public string Status { get; set; }
  158. [DataMember(Name = &quot;code&quot;)]
  159. public int Code { get; set; }
  160. [DataMember(Name = &quot;message&quot;)]
  161. public string Message { get; set; }
  162. }
  163. // different file
  164. using System;
  165. using System.Collections.Generic;
  166. using System.Linq;
  167. using System.Text;
  168. using System.ServiceModel;
  169. using System.ServiceModel.Web;
  170. [ServiceContract]
  171. public interface IAuthClient
  172. {
  173. [OperationContract,
  174. WebInvoke(
  175. UriTemplate = &quot;/?method=flickr.auth.getFrob&amp;format=json&amp;nojsoncallback=1&amp;api_key={key}&amp;api_sig={signature}&quot;,
  176. ResponseFormat = WebMessageFormat.Json,
  177. BodyStyle = WebMessageBodyStyle.Bare)]
  178. FrobResponse GetFrob(string signature, string key);
  179. [OperationContract,
  180. WebInvoke(
  181. UriTemplate = &quot;/?method=flickr.auth.getToken&amp;format=json&amp;nojsoncallback=1&amp;api_key={key}&amp;frob={frob}&amp;api_sig={signature}&quot;,
  182. ResponseFormat = WebMessageFormat.Json,
  183. BodyStyle = WebMessageBodyStyle.WrappedResponse)]
  184. Auth GetToken(string signature, string key, string frob);
  185. }
  186. // the actual client class.
  187. using System;
  188. using System.Collections.Generic;
  189. using System.Linq;
  190. using System.Text;
  191. using Amplify.Linq;
  192. public class AuthClient : FlickrClient&lt;IAuthClient&gt;
  193. {
  194. public AuthClient(string key, string secret)
  195. :base(key, secret)
  196. { }
  197. public AuthClient(string key, string secret, string token)
  198. :base(key, secret, token)
  199. { }
  200. public string GetFrob()
  201. {
  202. string md5 = new Hash() {
  203. {&quot;api_key&quot;, this.Key},
  204. {&quot;format&quot;, &quot;json&quot;},
  205. {&quot;method&quot;, &quot;flickr.auth.getFrob&quot;},
  206. {&quot;nojsoncallback&quot;, 1}
  207. }.ToMD5(this.Secret);
  208. FrobResponse response = this.Proxy.GetFrob(md5, this.Key);
  209. if (response.Code &gt; 0)
  210. throw new Exception(response.Message);
  211. return response.Frob.Content;
  212. }
  213. }</pre> <p class="blogger-labels">Labels: <a rel='tag' href="http://www.amptools.net/labels/Amplify.aspx">Amplify</a>, <a rel='tag' href="http://www.amptools.net/labels/C#.aspx">C#</a>, <a rel='tag' href="http://www.amptools.net/labels/Code.aspx">Code</a>, <a rel='tag' href="http://www.amptools.net/labels/CSharp.aspx">CSharp</a>, <a rel='tag' href="http://www.amptools.net/labels/Flickr.aspx">Flickr</a>, <a rel='tag' href="http://www.amptools.net/labels/JSON.aspx">JSON</a>, <a rel='tag' href="http://www.amptools.net/labels/REST.aspx">REST</a>, <a rel='tag' href="http://www.amptools.net/labels/WCF.aspx">WCF</a></p>
  214. </div>
  215. <div class="blog-footer">
  216. <a class="comment-link" href="https://www.blogger.com/comment.g?blogID=7043853799247804655&postID=8164722880411458481"location.href=https://www.blogger.com/comment.g?blogID=7043853799247804655&postID=8164722880411458481;><span style="text-transform:lowercase">0 Comments</span></a>
  217. <a class="comment-link" href="http://www.amptools.net/2008/07/using-wcf-to-access-flickr-json-api.aspx#links"><span style="text-transform:lowercase">Links to this post</span></a>
  218. <span class="item-action"><a href="http://www.blogger.com/email-post.g?blogID=7043853799247804655&postID=8164722880411458481" title="Email Post"><img class="icon-action" alt="" src="http://www.blogger.com:80/img/icon18_email.gif" height="13" width="18"/></a></span>
  219. <script type="text/javascript" src="http://w.sharethis.com/widget/?tabs=web%2Cemail&amp;charset=utf-8&amp;services=reddit%2Cdigg%2Cfacebook%2Cmyspace%2Cdelicious%2Cstumbleupon%2Ctechnorati%2Cpropeller%2Cblinklist%2Cmixx%2Cnewsvine%2Cgoogle_bmarks%2Cyahoo_myweb%2Cwindows_live%2Cfurl&amp;style=rotate&amp;publisher=baa2824f-9291-46c0-87b4-6d5a72508a05&amp;headerbg=%23dddddd&amp;inactivebg=%231bb601&amp;inactivefg=%2370eb00%09&amp;linkfg=%231bb601"></script>
  220. </div>
  221. </div>
  222. <div class="right">
  223. <h3>
  224. Connect
  225. </h3>
  226. <ul>
  227. <li>
  228. <a href="http://www.twitter.com/michaelherndon">
  229. <img src="/content/images/twitter-badge.png" alt="Twitter badge" />
  230. </a>
  231. </li>
  232. <li>
  233. <a href="http://www.facebook.com/profile.php?id=824905532">
  234. <img src="/content/images/facebook-badge.png" alt="Facebook badge" />
  235. </a>
  236. </li>
  237. <li>
  238. <a href="skype:michaelherndon?add">
  239. <img src="http://download.skype.com/share/skypebuttons/buttons/add_green_transparent_118x23.png" alt="Add me to Skype" />
  240. </a>
  241. </li>
  242. </ul>
  243. <h3>
  244. <a href="http://feeds.feedburner.com/amptoolsnet" rel="alternate" type="application/rss+xml">
  245. Subscribe in a reader <img src="http://www.feedburner.com/fb/images/pub/feed-icon32x32.png" style="vertical-align:middle" alt="" />
  246. </a>
  247. </h3>
  248. <ul>
  249. <li>
  250. </li>
  251. <li>
  252. <a href="http://feeds.feedburner.com/amptoolsnet">
  253. <img src="http://feeds.feedburner.com/~fc/amptoolsnet?bg=990066&amp;fg=CCCCCC&amp;anim=0" alt="" />
  254. </a>
  255. </li>
  256. <li>
  257. <a href="http://add.my.yahoo.com/rss?url=http://feeds.feedburner.com/amptoolsnet" title="amptools.net">
  258. <img src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif" alt="" />
  259. </a>
  260. </li>
  261. <li>
  262. <a href="http://fusion.google.com/add?feedurl=http://feeds.feedburner.com/amptoolsnet">
  263. <img src="http://buttons.googlesyndication.com/fusion/add.gif" alt="Add to Google Reader or Homepage"/>
  264. </a>
  265. </li>
  266. <li>
  267. <a href="http://www.pageflakes.com/subscribe.aspx?url=http://feeds.feedburner.com/amptoolsnet" title="Add to Pageflakes">
  268. <img src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif" alt="Add to Pageflakes"/>
  269. </a>
  270. </li>
  271. <li>
  272. <a href="http://www.bloglines.com/sub/http://feeds.feedburner.com/amptoolsnet" title="amptools.net" type="application/rss+xml">
  273. <img src="http://www.bloglines.com/images/sub_modern11.gif" alt="Subscribe in Bloglines" />
  274. </a>
  275. </li>
  276. <li>
  277. <a href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http://feeds.feedburner.com/amptoolsnet" title="amptools.net">
  278. <img src="http://www.newsgator.com/images/ngsub1.gif" alt="Subscribe in NewsGator Online" />
  279. </a>
  280. </li>
  281. </ul>
  282. <h3 class="sidebar-title">
  283. Previous Posts
  284. </h3>
  285. <ul id="recently">
  286. <li><a href="http://www.amptools.net/2008/11/simple-log-in-amplify.aspx">Simple Log in Amplify </a></li>
  287. <li><a href="http://www.amptools.net/2008/10/gallio-and-mb-unit-release-v304.aspx">Gallio and Mb-Unit release v3.0.4</a></li>
  288. <li><a href="http://www.amptools.net/2008/10/moving-amplify-to-git-hub.aspx">Moving Amplify To Git Hub...</a></li>
  289. <li><a href="http://www.amptools.net/2008/08/getting-datadirectory-folder-in-c-sharp.aspx">Getting the |DataDirectory| folder in C sharp</a></li>
  290. <li><a href="http://www.amptools.net/2008/08/ampliy-fusion-javascript-libraries.aspx">Amplify-Fusion, JavaScript libraries compatibility...</a></li>
  291. <li><a href="http://www.amptools.net/2008/07/amplify-wcf-twitter-api-client-library.aspx">Amplify&#39;s WCF Twitter API Client Library v0.2</a></li>
  292. <li><a href="http://www.amptools.net/2008/07/use-c-to-determine-where-and-what.aspx">Use C# to determine where and what version of java...</a></li>
  293. <li><a href="http://www.amptools.net/2008/07/using-wcf-to-access-flickr-json-api.aspx">Using WCF to access the Flickr JSON API</a></li>
  294. <li><a href="http://www.amptools.net/2008/07/sample-mixins-for-httprequestbase-to.aspx">Sample Mixins for HttpRequestBase to use with Asp....</a></li>
  295. <li><a href="http://www.amptools.net/2008/07/amplify-twittern-yet-another-c-twitter.aspx">Amplify&#39;s TwitterN, Yet Another C# Twitter REST AP...</a></li>
  296. </ul>
  297. <h3 class="sidebar-title">
  298. Archives
  299. </h3>
  300. <ul class="archive-list">
  301. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_03_30_index.aspx">03.30.2008</a></li>
  302. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_04_06_index.aspx">04.06.2008</a></li>
  303. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_06_08_index.aspx">06.08.2008</a></li>
  304. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_07_06_index.aspx">07.06.2008</a></li>
  305. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_07_13_index.aspx">07.13.2008</a></li>
  306. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_07_20_index.aspx">07.20.2008</a></li>
  307. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_07_27_index.aspx">07.27.2008</a></li>
  308. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_08_03_index.aspx">08.03.2008</a></li>
  309. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_08_10_index.aspx">08.10.2008</a></li>
  310. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_10_26_index.aspx">10.26.2008</a></li>
  311. <li><a href="http://www.amptools.net/blogs/michaelherndon/archives/2008_11_02_index.aspx">11.02.2008</a></li>
  312. </ul>
  313. </div>
  314. </asp:Content>