{"id":15,"date":"2015-01-27T09:45:10","date_gmt":"2015-01-27T15:45:10","guid":{"rendered":"http:\/\/www.teamdesk.net\/blog\/2015\/01\/using-rest-api-in-teamdesk-promo\/"},"modified":"2015-01-27T09:45:10","modified_gmt":"2015-01-27T15:45:10","slug":"using-rest-api-in-teamdesk-promo","status":"publish","type":"post","link":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/","title":{"rendered":"Using REST API in TeamDesk Promo"},"content":{"rendered":"<p><a href=\"http:\/\/www.teamdesk.net\/\">Our promo site<\/a> is powered by C#, ASP.NET Webpages and three TeamDesk databases holding the data for it \u2013 Database Library, Testimonials and Experts. As we recently finished site redesign, unifying look and feel for various site parts, we&#39;ve also switched from SOAP-based data retrieval to REST API. While in this article we&#39;ll share our findings concentrating on Experts as an example \u2013 as this part not only reads the data but posts new leads into the database \u2013 many pieces of the code are available for reuse as they are capable to deal with any application and any type of data.<\/p>\n<h2>Planning Functionality<\/h2>\n<p>As we want search engines to index the content, we are performing all data operations server-side \u2013 we extract the information from Experts database via the API and render it as a part of the page to pretend search engine it is a static content. Next, we do not want to bother the database to return fresh set of data on each and every page view \u2013 while REST API supports conditional caching, experts update their information infrequently. In order to decrease API workload and speed up page rendering we are caching information used often in memory for next 10 minutes unconditionally and only then perform conditional call to retrieve the data.<\/p>\n<p>Next, we&#39;ve switched &quot;Contact Expert&quot; form from sending data directly to database via web-to-record functionality to send the data to promo site first. The site performs basic validation for mandatory fields and e-mail address correctness and displays messages if data validation has not passed. Also this approach would enable us to extend the functionality with, say, CAPTCHA validation. Only when the data is completely valid we send it to a database via REST API.<\/p>\n<p><!--more--><\/p>\n<h2>Dealing with JSON<\/h2>\n<p>To deal with JSON input and output we&#39;ve chosen excellent <a href=\"https:\/\/www.nuget.org\/packages\/Newtonsoft.Json\/\">Newtonsoft.Json<\/a> library \u2013 it has reach capabilities, good throughput and tons of options to tweak every piece of serialization and deserialization process. The library is able to serialize and deserialize JSON both from and to .NET <em>dynamic<\/em> types and to C# classes. We have created <em>model <\/em>classes for both Experts and Leads as with strongly-typed approach we can minimize typos and take advantage of IntelliSense in the IDE. In most cases names of class members match the column names in the database. In case column name cannot be expressed as a member identifier, thanks to the library, mapping between JSON name and member name can be controlled via member&#39;s attribute.<\/p>\n<p><span style=\"color: blue; font-family: Consolas;\"><span style=\"font-size: 9pt; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Expert<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Id;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Photo;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Name;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Location;<br \/>&#0160;&#0160;&#0160;&#0160;[<span style=\"color: #2b91af;\">JsonProperty<span style=\"color: black;\">(<span style=\"color: #a31515;\">&quot;TeamDesk Experience&quot;<span style=\"color: black;\">)]<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Experience;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> PR;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> HR;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> User;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Description;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">bool<span style=\"color: black;\"> Overbooked;<br \/>}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Lead<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Reference to User in Experts<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Expert;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Name;<br \/>&#0160;&#0160;&#0160;&#0160;[<span style=\"color: #2b91af;\">JsonProperty<span style=\"color: black;\">(<span style=\"color: #a31515;\">&quot;E-Mail&quot;<span style=\"color: black;\">)]<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Email;<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Question;<br \/>} <\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<h2>Sending and receiving<\/h2>\n<p>To send and receive the data we are utilizing .NET 4.5 <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.net.http.httpclient(v=vs.118).aspx\">HttpClient<\/a> class. <em>HttpClient<\/em> builds the request message and parses the response, but actual data interchange logic is performed via <em>message transport<\/em> class. We want the transport to be able to receive compressed content and cache it but <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.net.http.httpclienthandler(v=vs.118).aspx\">default message transport<\/a> due to portability issues supports only compression options. In order to support caching we need to use <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.net.http.webrequesthandler(v=vs.110).aspx\">another transport<\/a> class. It is desktop-specific, but it&#39;s ok for us. We wrote small function that sets up HttpClient with all the options we need:<\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: #2b91af;\">HttpClient<span style=\"color: black;\"> CreateClient()<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">HttpClient<span style=\"color: black;\">(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">WebRequestHandler<span style=\"color: black;\">() {<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;AutomaticDecompression = <span style=\"color: #2b91af;\">DecompressionMethods<span style=\"color: black;\">.GZip<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;| <span style=\"color: #2b91af;\">DecompressionMethods<span style=\"color: black;\">.Deflate<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;});<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>} <\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p>Caching support is completely transparent \u2013 as long as data is in the cache and server reports cached copy is still valid via HTTP 304 status code <em>HttpClient<\/em> returns cached copy with HTTP 200 OK status as the request was actually made.<\/p>\n<h2>Caching<\/h2>\n<p>Caching facility provided by <em>HttpClient<\/em> allows us to minimize the traffic between the site and the database but API calls are still performed to ensure the validity of cached data. As experts&#39; information is changed infrequently we can trade freshness for reducing the number of API calls. To do this we organize in-memory cache to keep parsed API response for 10 minutes. Once entry is missing or was removed from the cache we&#39;ll call API again and place the result back to the cache shifting expiration time for 10 more minutes. Here is another small helper class with a single <em>Get<\/em> method. The method is generic and is capable to cache any output type under any key type.<\/p>\n<p><span style=\"font-size: 9pt;\"><span style=\"color: blue;\"><span style=\"font-family: Consolas; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Cache<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> TValue Get&lt;TKey, TValue&gt;(TKey key, <span style=\"color: #2b91af;\">Func<span style=\"color: black;\">&lt;TKey, TValue&gt; loader)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">where<span style=\"color: black;\"> TValue : <span style=\"color: blue;\">class<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">string<span style=\"color: black;\"> cacheKey = <span style=\"color: blue;\">typeof<span style=\"color: black;\">(<span style=\"color: #2b91af;\">Cache<span style=\"color: black;\">).FullName + <span style=\"color: #a31515;\">&quot;$&quot;<span style=\"color: black;\"> + <br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160; typeof<span style=\"color: black;\">(<span style=\"color: #2b91af;\">TValue<span style=\"color: black;\">).FullName + <span style=\"color: #a31515;\">&quot;$&quot;<span style=\"color: black;\"> + <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160; key.ToString();<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;TValue result = <span style=\"color: #2b91af;\">MemoryCache<span style=\"color: black;\">.Default.Get(cacheKey) <span style=\"color: blue;\">as<span style=\"color: black;\"> TValue;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(result == <span style=\"color: blue;\">null<span style=\"color: black;\">)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;result = loader(key);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;result = <span style=\"color: #2b91af;\">MemoryCache<span style=\"color: black;\">.Default.AddOrGetExisting(cacheKey, result,<br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;DateTimeOffset<span style=\"color: black;\">.Now + Timeout) <span style=\"color: blue;\">as<span style=\"color: black;\"> TValue ?? result;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> result;<br \/>&#0160;&#0160;&#0160;&#0160;}<\/p>\n<p>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">readonly<span style=\"color: black;\"> <span style=\"color: #2b91af;\">TimeSpan<span style=\"color: black;\"> Timeout = <span style=\"color: #2b91af;\">TimeSpan<span style=\"color: black;\">.FromMinutes(10);<br \/>}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<h2>Generic Data Retrieval<\/h2>\n<p>Our <em>ApiHelper<\/em> class has another couple methods to help dealing with <em>select<\/em> API calls. As our data retrieval tasks are not limited to Experts, the <em>Select<\/em> method is generic to deserializing the output into a list of objects of any type. Any unsuccessful HTTP status code results to an exception which is handled globally. <em>SelectOne<\/em> is a shorthand method returning first record in the list, if any. <em>Literal<\/em> method encodes the quotes inside the text and adds quotes around for use in filter conditions.<\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Literal(<span style=\"color: blue;\">string<span style=\"color: black;\"> value)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(value == <span style=\"color: blue;\">null<span style=\"color: black;\">) <span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #a31515;\">&quot;null&quot;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #2b91af;\">String<span style=\"color: black;\">.Concat(<span style=\"color: #a31515;\">&#39;&quot;&#39;<span style=\"color: black;\">, value.Replace(<span style=\"color: #a31515;\">@&quot;\\&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">@&quot;\\\\&quot;<span style=\"color: black;\">).Replace(<span style=\"color: #a31515;\">@&quot;&quot;&quot;&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">@&quot;\\&quot;&quot;&quot;<span style=\"color: black;\">), <span style=\"color: #a31515;\">&#39;&quot;&#39;<span style=\"color: black;\">);<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/><span style=\"color: #00b050;\"><br \/><span style=\"color: black;\">&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: #2b91af;\">IEnumerable<span style=\"color: black;\">&lt;T&gt; Select&lt;T&gt;(<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> apiPath,<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> table, <br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;IEnumerable<span style=\"color: black;\">&lt;<span style=\"color: blue;\">string<span style=\"color: black;\">&gt; columns = <span style=\"color: blue;\">null<span style=\"color: black;\">,&#0160;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">string<span style=\"color: black;\"> filter = <span style=\"color: blue;\">null<span style=\"color: black;\">,<br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;IEnumerable<span style=\"color: black;\">&lt;<span style=\"color: blue;\">string<span style=\"color: black;\">&gt; sort = <span style=\"color: blue;\">null<span style=\"color: black;\">,<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;int<span style=\"color: black;\"> top = 0, <span style=\"color: blue;\">int<span style=\"color: black;\"> skip = 0)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ apiPath is in format: <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160; \/\/ https:\/\/www.teamdesk.net\/secure\/api\/v2\/&lt;app-id&gt;\/&lt;token&gt;<span style=\"color: black;\"><\/p>\n<p>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Build full REST API URL including parameters<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">StringBuilder<span style=\"color: black;\"> apiUrl = <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">StringBuilder<span style=\"color: black;\">(apiPath)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Append(<span style=\"color: #a31515;\">&#39;\/&#39;<span style=\"color: black;\">)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Append(<span style=\"color: #2b91af;\">Uri<span style=\"color: black;\">.EscapeDataString(table))<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160; .Append(<span style=\"color: #a31515;\">&quot;\/select.json&quot;<span style=\"color: black;\">);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">char<span style=\"color: black;\"> sep = <span style=\"color: #a31515;\">&#39;?&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(columns != <span style=\"color: blue;\">null<span style=\"color: black;\"> &amp;&amp; columns.Any())<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl.Append(sep).Append(<span style=\"color: #2b91af;\">String<span style=\"color: black;\">.Join(<span style=\"color: #a31515;\">&quot;&amp;&quot;<span style=\"color: black;\">, <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;columns.Select(c =&gt; <span style=\"color: #a31515;\">&quot;column=&quot;<span style=\"color: black;\"> + <span style=\"color: #2b91af;\">Uri<span style=\"color: black;\">.EscapeDataString(c))));<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sep = <span style=\"color: #a31515;\">&#39;&amp;&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(!<span style=\"color: #2b91af;\">String<span style=\"color: black;\">.IsNullOrEmpty(filter))<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl.Append(sep).Append(<span style=\"color: #a31515;\">&quot;filter=&quot;<span style=\"color: black;\">)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Append(<span style=\"color: #2b91af;\">Uri<span style=\"color: black;\">.EscapeDataString(filter));<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sep = <span style=\"color: #a31515;\">&#39;&amp;&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(sort != <span style=\"color: blue;\">null<span style=\"color: black;\"> &amp;&amp; sort.Any())<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl.Append(sep).Append(<span style=\"color: #2b91af;\">String<span style=\"color: black;\">.Join(<span style=\"color: #a31515;\">&quot;&amp;&quot;<span style=\"color: black;\">,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sort.Select(c =&gt; <span style=\"color: #a31515;\">&quot;sort=&quot;<span style=\"color: black;\"> + <span style=\"color: #2b91af;\">Uri<span style=\"color: black;\">.EscapeDataString(c))));<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sep = <span style=\"color: #a3151\n5;\">&#39;&amp;&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(top != 0)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl.Append(sep).Append(<span style=\"color: #a31515;\">&quot;top=&quot;<span style=\"color: black;\">).Append(top);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sep = <span style=\"color: #a31515;\">&#39;&amp;&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(skip != 0)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl.Append(sep).Append(<span style=\"color: #a31515;\">&quot;skip=&quot;<span style=\"color: black;\">).Append(skip);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;sep = <span style=\"color: #a31515;\">&#39;&amp;&#39;<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Call the API<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">using<span style=\"color: black;\">(<span style=\"color: blue;\">var<span style=\"color: black;\"> client = CreateClient())<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ return a list of objects of type T<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #2b91af;\">JsonConvert<span style=\"color: black;\">.DeserializeObject&lt;<span style=\"color: #2b91af;\">IEnumerable<span style=\"color: black;\">&lt;T&gt;&gt;(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;client<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.GetAsync(apiUrl.ToString())<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ will throw on failure<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Result.EnsureSuccessStatusCode()<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Content.ReadAsStringAsync().Result);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;}<\/p>\n<p>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> T SelectOne&lt;T&gt;(<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> apiPath,<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> table,<br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;IEnumerable<span style=\"color: black;\">&lt;<span style=\"color: blue;\">string<span style=\"color: black;\">&gt; columns = <span style=\"color: blue;\">null<span style=\"color: black;\">,<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> filter = <span style=\"color: blue;\">null<span style=\"color: black;\">)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> Select&lt;T&gt;(apiPath, table, columns, filter).FirstOrDefault();<br \/>&#0160;&#0160;&#0160;&#0160;}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><br \/><span style=\"color: black;\"><span style=\"background-color: white;\">&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>}<\/span><\/span><\/span> <\/span><\/span><\/p>\n<h2>Retrieving Experts<\/h2>\n<p>Enough with generic helpers, now let&#39;s do some actual work. On <a href=\"http:\/\/www.teamdesk.net\/experts\">experts<\/a> page we render short info as tiles, while the page <a href=\"http:\/\/www.teamdesk.net\/experts?id=16\">dedicated to an expert<\/a> contains much longer description and a contact form if expert is available. Let&#39;s create <em>Experts<\/em> class \u2013 <em>Service<\/em> property retrieves base path to API from configuration file, <em>List<\/em> method with no parameters retrieves (probably in-memory cached copy of) the list of experts to render tiles, <em>Get<\/em> method retrieves single expert information to render the page \u2013 in-memory caching is not used in this case. <em>GetPhotoURL<\/em> converts <em>filename;revision;guid<\/em> value reported for attachment columns into an URL to <em>attachment<\/em> REST API method.<\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Experts<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">internal<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> Service<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ https:\/\/www.teamdesk.net\/secure\/api\/v2\/&lt;app-id&gt;\/&lt;token&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">get<span style=\"color: black;\"> { <span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #2b91af;\">ConfigurationManager<span style=\"color: black;\">.AppSettings[<span style=\"color: #a31515;\">&quot;Experts.REST&quot;<span style=\"color: black;\">]; }<br \/>&#0160;&#0160;&#0160;&#0160;}<\/p>\n<p>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Retrieves the list of experts &#8211; either via cached copy or via API call<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: #2b91af;\">IEnumerable<span style=\"color: black;\">&lt;<span style=\"color: #2b91af;\">Expert<span style=\"color: black;\">&gt; List()<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Cache<span style=\"color: black;\">.Get(<span style=\"color: #a31515;\">&quot;Experts&quot;<span style=\"color: black;\">, _ =&gt; <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\">.Select&lt;<span style=\"color: #2b91af;\">Expert<span style=\"color: black;\">&gt;(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Service,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;Expert&quot;<span style=\"color: black;\">, <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\">[] {<br \/><span style=\"color: #a31515;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&quot;Id&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Photo &quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Name&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Location&quot;<span style=\"color: black;\">,&#0160;<br \/><span style=\"color: #a31515;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&quot;PR&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;HR&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;TeamDesk Experience&quot;<br \/><span style=\"color: black;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;},<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;[Active]&quot;<span style=\"color: black;\">,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">Enumerable<span style=\"color: black;\">.Repeat(<span style=\"color: #a31515;\">&quot;Date Modified\/\/DESC&quot;<span style=\"color: black;\">, 1)));<br \/>&#0160;&#0160;&#0160;&#0160;}<\/p>\n<p>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Retrieves the expert by key, does not cache in memory<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Expert<span style=\"color: black;\"> Get(<span style=\"color: blue;\">string<span style=\"color: black;\"> key)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> <span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\">.SelectOne&lt;<span style=\"color: #2b91af;\">Expert<span style=\"color: black;\">&gt;(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Service,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;Expert&quot;<span style=\"color: black;\">, <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\">[] {<br \/><span style=\"color: #a31515;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&quot;Id&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Photo &quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Name&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Location&quot;<span style=\"color: black;\">,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;PR&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;HR&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;TeamDesk Experience&quot;<span style=\"color: black;\">,<br \/><span style=\"color: #a31515;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&quot;Description&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;Overbooked&quot;<span style=\"color: black;\">, <span style=\"color: #a31515;\">&quot;User&quot;<br \/><span style=\"color: black;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160; },<span style=\"color: #2b91af;\"><br \/><span style=\"color: black;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;[Id]=&quot;<span style=\"color: black;\"> + <span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\">.Literal(key));<br \/>&#0160;&#0160;&#0160;&#0160;}<\/p>\n<p>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Get URL to \/Expert\/Photo\/attachment\/&lt;guid&gt; method<br \/>&#0160;&#0160;&#0160; \/\/ (Public Access is on for Photo column)<br \/><span style=\"color: black;\">&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">string<span style=\"color: black;\"> GetPhotoURL(<span style=\"color: blue;\">string<span style=\"color: black;\"> value)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ strip off authorization, add table, field and method<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\"> value != <span style=\"color: blue;\">null<span style=\"color: black;\"> ? <br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Experts<span style=\"color: black;\">.Service.Substring(0, <span style=\"color: #2b9\n1af;\">Experts<span style=\"color: black;\">.Service.Length &#8211; 33) +<br \/> <span style=\"color: #a31515;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&quot;\/Expert\/Photo\/attachment\/&quot;<span style=\"color: black;\"> + <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;value.Substring(value.Length &#8211; 36) : <span style=\"color: blue;\">null<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span> <\/span><\/p>\n<p>With help of Experts class page rendering looks like:<\/p>\n<p><span style=\"color: blue; font-size: 9pt;\"><span style=\"font-family: Consolas;\"><span style=\"background-color: white;\">&lt;<span style=\"color: maroon;\">article<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/><\/span><\/span><\/span><\/span><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">foreach<span style=\"color: black;\">(<span style=\"color: blue;\">var<span style=\"color: black;\"> expert <span style=\"color: blue;\">in<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Experts<span style=\"color: black;\">.List())<br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">section<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">img<span style=\"color: black;\"> <span style=\"color: red;\">src<span style=\"color: blue;\">=&quot;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"color: #2b91af;\"><span style=\"background-color: white;\">Experts<span style=\"color: black;\">.GetPhotoURL(expert.Photo)<span style=\"color: blue;\">&quot;<span style=\"color: black;\"> <span style=\"color: blue;\">\/&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">h3<span style=\"color: blue;\">&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">expert.Name<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">h3<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">p<span style=\"color: blue;\">&gt;<span style=\"color: black;\">from <\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">expert.Location<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">p<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">table<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">tr<span style=\"color: blue;\">&gt;&lt;<span style=\"color: maroon;\">th<span style=\"color: blue;\">&gt;<span style=\"color: black;\">Starting Project Rate<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">th<span style=\"color: blue;\">&gt;&lt;<span style=\"color: maroon;\">td<span style=\"color: blue;\">&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">expert.PR<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">td<span style=\"color: blue;\">&gt;&lt;\/<span style=\"color: maroon;\">tr<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">tr<span style=\"color: blue;\">&gt;&lt;<span style=\"color: maroon;\">th<span style=\"color: blue;\">&gt;<span style=\"color: black;\">Hourly Rate<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">th<span style=\"color: blue;\">&gt;&lt;<span style=\"color: maroon;\">td<span style=\"color: blue;\">&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">expert.HR<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">td<span style=\"color: blue;\">&gt;&lt;\/<span style=\"color: maroon;\">tr<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">table<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">ul<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"background-color: yellow;\">@<\/span><span style=\"color: blue;\"><span style=\"background-color: white;\">foreach<span style=\"color: black;\">(<span style=\"color: blue;\">var<span style=\"color: black;\"> exp <span style=\"color: blue;\">in<span style=\"color: black;\"> expert.Experience.Split(<span style=\"color: #a31515;\">&#39;,&#39;<span style=\"color: black;\">))<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">li<span style=\"color: black;\"> <span style=\"color: red;\">class<span style=\"color: blue;\">=&quot;ui-icon-check&quot;&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">exp<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">li<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">ul<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;<span style=\"color: maroon;\">a<span style=\"color: black;\"> <span style=\"color: red;\">href<span style=\"color: blue;\">=&quot;~\/experts?id=<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"color: black;\"><span style=\"background-color: yellow;\">@<\/span><span style=\"background-color: white;\">expert.Id<span style=\"color: blue;\">&quot;&gt;<span style=\"color: black;\">View expert profile<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">a<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">section<span style=\"color: blue;\">&gt;<span style=\"color: black;\"><br \/>}<br \/><span style=\"color: blue;\">&lt;\/<span style=\"color: maroon;\">article<span style=\"color: blue;\">&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span> <\/span><\/p>\n<h2>Creating Expert&#39;s Leads<\/h2>\n<p>Let&#39;s add one more method to <em>ApiHelper<\/em> class \u2013 the method to create single record. <em>Create<\/em> API method responds with individual status for every row passed in and while using strongly typed data for input we are taking advantage of parsing the output as a <em>dynamic<\/em> object \u2013 just as a proof of concept.<\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static<span style=\"color: black;\"> <span style=\"color: blue;\">void<span style=\"color: black;\"> CreateOne&lt;T&gt;(<span style=\"color: blue;\">string<span style=\"color: black;\"> apiPath, <span style=\"color: blue;\">string<span style=\"color: black;\"> table, T data)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">string<span style=\"color: black;\"> apiUrl = <span style=\"color: #2b91af;\">String<span style=\"color: black;\">.Format(<span style=\"color: #a31515;\">&quot;{0}\/{1}\/create.json&quot;<span style=\"color: black;\">, <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiPath, <br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Uri<span style=\"color: black;\">.EscapeDataString(table));<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">using<span style=\"color: black;\">(<span style=\"color: blue;\">var<span style=\"color: black;\"> client = CreateClient())<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">dynamic<span style=\"color: black;\"> result = <span style=\"color: #2b91af;\">JsonConvert<span style=\"color: black;\">.DeserializeObject(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;client<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.PostAsync(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;apiUrl,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">StringContent<span style=\"color: black;\">(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">JsonConvert<span style=\"color: black;\">.SerializeObject(<br \/><span style=\"color: #2b91af;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Enumerable<span style=\"color: black;\">.Repeat(data, 1)),<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">Encoding<span style=\"color: black;\">.UTF8,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #a31515;\">&quot;application\/json&quot;<span style=\"color: black;\">))<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Result.EnsureSuccessStatusCode()<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;.Content.ReadAsStringAsync().Result);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(result[0].status != 201) <span style=\"color: green;\">\/\/ not created? Throw!<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">throw<span style=\"color: black;\"> <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">InvalidOperationException<span style=\"color: black;\">(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;(<span style=\"color: blue;\">string<span style=\"color: black;\">)result[0].errors[0].message);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>} <\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p>Another method in <em>Experts<\/em> class fills <em>Lead <\/em>model from a form and calls <em>ApiHelper<\/em><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static class<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Experts<span style=\"color: black;\"><br \/>{<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">public<span style=\"color: black;\"> <span style=\"color: blue;\">static void<span style=\"color: black;\"> AddLead(<span style=\"color: blue;\">string<span style=\"color: black;\"> expert, <span style=\"color: blue;\">string<span style=\"color: black;\"> name,<br \/><span style=\"color: blue;\">&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;string<span style=\"color: black;\"> email, <span style=\"color: blue;\">string<span style=\"color: black;\"> question)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">ApiHelper<span style=\"color: black;\">.CreateOne(<span style=\"color: #2b91af;\">Experts<span style=\"color: black;\">.Service, <span style=\"color: #a31515;\">&quot;Lead&quot;<span style=\"color: black;\">, <span style=\"color: blue;\">new<span style=\"color: black;\"> <span style=\"color: #2b91af;\">Lead<span style=\"color: black;\">() { <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Expert = expert,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Name = name,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Email = email,<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Question = question<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;});<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>} <\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p>And on the page we are doing the following.<\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: yellow;\">@{<\/span><span style=\"background-color: white;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">Expert<span style=\"color: black;\"> expert = <span style=\"color: #2b91af;\">Experts<span style=\"color: black;\">.Get(Request.QueryString[<span style=\"color: #a31515;\">&quot;id&quot;<span style=\"color: black;\">]);<br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ Set up form validation rules<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: green;\">\/\/ &#8230;<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">if<span style=\"color: black;\">(IsPost &amp;&amp; Validation.IsValid() &amp;&amp; !expert.Overbooked)<br \/>&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">try<span style=\"color: black;\"><br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: #2b91af;\">Experts<span style=\"color: black;\">.AddLead(<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;expert.User, <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Request.Form[<span style=\"color: #a31515;\">&quot;name&quot;<span style=\"color: black;\">], <br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Request.Form[<span style=\"color: #a31515;\">&quot;email&quot;<span style=\"color: black;\">],<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Request.Form[<span style=\"color: #a31515;\">&quot;question&quot;<span style=\"color: black;\">]);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Response.Redirect(<span style=\"color: #a31515;\">&quot;~\/experts&quot;<span style=\"color: black;\">);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">return<span style=\"color: black;\">;<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;<span style=\"color: blue;\">catch<span style=\"color: black;\">(<span style=\"color: #2b91af;\">Exception<span style=\"color: black;\"> ex)<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;{<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;Validation.AddFormError(ex.Message);<br \/>&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;&#0160;}<br \/>&#0160;&#0160;&#0160;&#0160;}<br \/><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"background-color: yellow;\">}<\/span><br \/><span style=\"color: darkgreen;\"><span style=\"background-color: white;\">&lt;!&#8211; Render expert page &#8211;&gt;<\/span><\/span><\/span><\/p>\n<h2>Resume<\/h2>\n<p>In this article we shared some techniques we&#39;ve used to power our promo-site with REST API. While we do not demand to follow our model precisely as there might be some restrictions, or in contrast, some technologies that may require or make possible to use different approaches to the same task, we hope you&#39;ve found our samples useful \u2013 either in form of reusable code or ideas on code and data organization.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Our promo site is powered by C#, ASP.NET Webpages and three TeamDesk databases holding the data for it \u2013 Database Library, Testimonials and Experts. As we recently finished site redesign, unifying look and feel for various site parts, we&#39;ve also switched from SOAP-based data retrieval to REST API. While in this article we&#39;ll share our [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,2],"tags":[7,6,8,9,11,10,5],"class_list":["post-15","post","type-post","status-publish","format-standard","hentry","category-behind-the-scenes","category-tips-tricks","tag-net","tag-api","tag-asp-net","tag-asp-net-web-pages","tag-c","tag-razor","tag-rest"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Using REST API in TeamDesk Promo - TeamDesk Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using REST API in TeamDesk Promo - TeamDesk Blog\" \/>\n<meta property=\"og:description\" content=\"Our promo site is powered by C#, ASP.NET Webpages and three TeamDesk databases holding the data for it \u2013 Database Library, Testimonials and Experts. As we recently finished site redesign, unifying look and feel for various site parts, we&#039;ve also switched from SOAP-based data retrieval to REST API. While in this article we&#039;ll share our [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/\" \/>\n<meta property=\"og:site_name\" content=\"TeamDesk Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-01-27T15:45:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2024\/01\/logo_og.png\" \/>\n\t<meta property=\"og:image:width\" content=\"600\" \/>\n\t<meta property=\"og:image:height\" content=\"315\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kirill Bondar\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kirill Bondar\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/\"},\"author\":{\"name\":\"Kirill Bondar\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\"},\"headline\":\"Using REST API in TeamDesk Promo\",\"datePublished\":\"2015-01-27T15:45:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/\"},\"wordCount\":1982,\"commentCount\":0,\"keywords\":[\".NET\",\"API\",\"ASP.NET\",\"ASP.NET Web Pages\",\"C#\",\"Razor\",\"REST\"],\"articleSection\":[\"Behind the Scenes\",\"Tips &amp; Tricks\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/\",\"name\":\"Using REST API in TeamDesk Promo - TeamDesk Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\"},\"datePublished\":\"2015-01-27T15:45:10+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/using-rest-api-in-teamdesk-promo\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using REST API in TeamDesk Promo\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\",\"name\":\"TeamDesk Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\",\"name\":\"Kirill Bondar\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"caption\":\"Kirill Bondar\"},\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/author\\\/kirill-bondar\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using REST API in TeamDesk Promo - TeamDesk Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/","og_locale":"en_US","og_type":"article","og_title":"Using REST API in TeamDesk Promo - TeamDesk Blog","og_description":"Our promo site is powered by C#, ASP.NET Webpages and three TeamDesk databases holding the data for it \u2013 Database Library, Testimonials and Experts. As we recently finished site redesign, unifying look and feel for various site parts, we&#39;ve also switched from SOAP-based data retrieval to REST API. While in this article we&#39;ll share our [&hellip;]","og_url":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/","og_site_name":"TeamDesk Blog","article_published_time":"2015-01-27T15:45:10+00:00","og_image":[{"width":600,"height":315,"url":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2024\/01\/logo_og.png","type":"image\/png"}],"author":"Kirill Bondar","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kirill Bondar","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/#article","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/"},"author":{"name":"Kirill Bondar","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2"},"headline":"Using REST API in TeamDesk Promo","datePublished":"2015-01-27T15:45:10+00:00","mainEntityOfPage":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/"},"wordCount":1982,"commentCount":0,"keywords":[".NET","API","ASP.NET","ASP.NET Web Pages","C#","Razor","REST"],"articleSection":["Behind the Scenes","Tips &amp; Tricks"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/","url":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/","name":"Using REST API in TeamDesk Promo - TeamDesk Blog","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/#website"},"datePublished":"2015-01-27T15:45:10+00:00","author":{"@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2"},"breadcrumb":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/using-rest-api-in-teamdesk-promo\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.teamdesk.net\/blog\/"},{"@type":"ListItem","position":2,"name":"Using REST API in TeamDesk Promo"}]},{"@type":"WebSite","@id":"https:\/\/www.teamdesk.net\/blog\/#website","url":"https:\/\/www.teamdesk.net\/blog\/","name":"TeamDesk Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.teamdesk.net\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2","name":"Kirill Bondar","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","caption":"Kirill Bondar"},"url":"https:\/\/www.teamdesk.net\/blog\/author\/kirill-bondar\/"}]}},"_links":{"self":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/15","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/comments?post=15"}],"version-history":[{"count":0,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/media?parent=15"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/categories?post=15"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/tags?post=15"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}