Microsoft MVP Logo

    <p>In the past <a href="">I've complained</a> about the Salesforce SOAP API for reading/writing your CRM databases. Last year Salesforce added a new API, one founded on RESTful principals, for developers to work with. I wish it was implemented as an <a href="">OData</a> service, but I guess the Salesforce guys are stuck behind the times. </p> <p>At any rate, I had a need to read/write to a Salesforce instance and couldn't bear to use their <a href="">SOAP API</a> again so I decided to give the <a href="">REST API</a> a go. Their developer site doesn't do that much in the way of help for .NET developers (there is some, but not much)... everything is really skewed towards PHP or their own APEX language. After some searching I found <a href="">Dan Boris'</a> series of <a href="">Salesforce related posts</a>. These are good and he covers a lot of good things such as:</p> <ul> <li>Authentication:  <ul> <li><a href="">Salesforce REST API</a>  </li><li><a href="">Salesforce REST API Access Token</a></li></ul> </li><li>Reading Data  <ul> <li><a href="">Salesforce REST API Read Record</a>  </li><li><a href="">Salesforce REST API Query</a>  </li><li><a href="">Salesforce REST API Query Deserialization</a></li></ul> </li><li>Writing Data  <ul> <li><a href="">Salesforce REST API Update &amp; Delete</a>  </li><li><a href="">Salesforce REST API Record Creation</a></li></ul></li></ul> <p>Dan's posts talk about using the method of authentication where you create an app that contains an embedded browser control and you get the user using t your app to login to Salesforce. Then your app grabs the OAuth token and include that with all future requests. Before you do this you need to configure a new remote access app for your Salesforce account. This is done by logging in and going to <strong>SETUP &gt; DEVELOP &gt; REMOTE ACCESS</strong>. Click <strong>NEW </strong>and create a new remote access app. One of the fields it will give you is a callback URL that is required. This is used by Salesforce to redirect the user back to a specific URL after a successful login. In a web app this makes sense but not if you want to use this within a console app or a service. What I do is put just a dummy URN in there that I'll look for later like <strong>resttest:callback</strong>.</p> <p>Now, Dan's stuff works great in many cases, but not if you want to create an app that runs like a service and automatically logs in and does some stuff with the API without user interaction. The way you authenticate with Salesforce is using OAuth 2.0. OAuth 2.0 supports multiple authentication flows and Salesforce supports many of them as outlined in their SDK: <a href="">Authenticating Remote Access Application OAuth</a> &amp; discussed on their DeveloperForce site: <a href="">Digging Deeper into OAuth 2.0 on</a>. In my scenario I want to focus on creating an app that runs as a service to use the REST API without any user action required for logging in. This is the least secure because it means I have to store a username &amp; password somewhere, but that's just the ante for playing the game. So, in this case I want to use the <a href="">OAuth 2.0 Username &amp; Password Flow</a>.</p> <p>So, to authenticate you do something like this using the OAuth 2.0 Username &amp; Password flow: </p> <div id="codeSnippetWrapper" class="csharpcode-wrapper"> <div id="codeSnippet" class="csharpcode"><pre class="alt"><span id="lnum1" class="lnum">   1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> AuthenticateToSalesforce(){</pre><pre class="alteven"><span id="lnum2" class="lnum">   2:</span>   <span class="kwrd">string</span> uri = <span class="str">""</span>;</pre><pre class="alt"><span id="lnum3" class="lnum">   3:</span>  </pre><pre class="alteven"><span id="lnum4" class="lnum">   4:</span>   var webClient = <span class="kwrd">new</span> WebClient() {</pre><pre class="alt"><span id="lnum5" class="lnum">   5:</span>     BaseAddress = uri</pre><pre class="alteven"><span id="lnum6" class="lnum">   6:</span>   };</pre><pre class="alt"><span id="lnum7" class="lnum">   7:</span>  </pre><pre class="alteven"><span id="lnum8" class="lnum">   8:</span>   var collection = <span class="kwrd">new</span> NameValueCollection();</pre><pre class="alt"><span id="lnum9" class="lnum">   9:</span>   collection.Add(<span class="str">"grant_type"</span>, <span class="str">"password"</span>);</pre><pre class="alteven"><span id="lnum10" class="lnum">  10:</span>   collection.Add(<span class="str">"client_id"</span>, CONSUMER_KEY);</pre><pre class="alt"><span id="lnum11" class="lnum">  11:</span>   collection.Add(<span class="str">"client_secret"</span>, CONSUMER_SECRET);</pre><pre class="alteven"><span id="lnum12" class="lnum">  12:</span>   collection.Add(<span class="str">"username"</span>, SALESFORCE_USERNAME);</pre><pre class="alt"><span id="lnum13" class="lnum">  13:</span>   collection.Add(<span class="str">"password"</span>, SALESFORCE_PASSWORD_AND_SECRETKEY);</pre><pre class="alteven"><span id="lnum14" class="lnum">  14:</span>  </pre><pre class="alt"><span id="lnum15" class="lnum">  15:</span>   <span class="kwrd">byte</span>[] responseBytes = webClient.UploadValues(<span class="str">""</span>, <span class="str">"POST"</span>, collection);</pre><pre class="alteven"><span id="lnum16" class="lnum">  16:</span>   <span class="kwrd">string</span> response = Encoding.UTF8.GetString(responseBytes);</pre><pre class="alt"><span id="lnum17" class="lnum">  17:</span>   <span class="kwrd">string</span> decodedResponse = HttpUtility.UrlDecode(response);</pre><pre class="alteven"><span id="lnum18" class="lnum">  18:</span>   JavaScriptSerializer js = <span class="kwrd">new</span> JavaScriptSerializer();</pre><pre class="alt"><span id="lnum19" class="lnum">  19:</span>   var token = js.Deserialize&lt;TokenResponse&gt;(decodedResponse);</pre><pre class="alteven"><span id="lnum20" class="lnum">  20:</span> }</pre><pre class="alt"><span id="lnum21" class="lnum">  21:</span>  </pre><pre class="alteven"><span id="lnum22" class="lnum">  22:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> TokenResponse {</pre><pre class="alt"><span id="lnum23" class="lnum">  23:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> id { get; set; }</pre><pre class="alteven"><span id="lnum24" class="lnum">  24:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> issued_at { get; set; }</pre><pre class="alt"><span id="lnum25" class="lnum">  25:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> refresh_token { get; set; }</pre><pre class="alteven"><span id="lnum26" class="lnum">  26:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> instance_url { get; set; }</pre><pre class="alt"><span id="lnum27" class="lnum">  27:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> signature { get; set; }</pre><pre class="alteven"><span id="lnum28" class="lnum">  28:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> access_token { get; set; }</pre><pre class="alt"><span id="lnum29" class="lnum">  29:</span> }</pre></div></div>

    <p>As you can see I'm creating a Web request and passing in a handful of things in the header. Specifically I'm passing in the <strong>grant_type</strong> of "password" to signal I want to use the OAuth 2.0 Username &amp; Password flow. I'm also passing in the consumer key &amp; secret you get from creating the remote access app in your Salesforce account and finally the username &amp; password to authenticate with. This will return a JSON array (you can also get a XML response if you like) which I deserialize into a custom object that will pull everything I need. Specifically I need the <strong>instance_url </strong>(which is the URL of my Salesforce account) and the <strong>access_token</strong> which is what you need to include in all future requests. </p>
    <p>Once you have the token, you can use the REST API to read &amp; write data like Dan shows in his posts I linked to above, or like this:</p>
    <div id="codeSnippetWrapper" class="csharpcode-wrapper">
    <div id="codeSnippet" class="csharpcode"><pre class="alt"><span id="lnum1" class="lnum">   1:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> QuerySalesforce(){</pre><pre class="alteven"><span id="lnum2" class="lnum">   2:</span>   <span class="rem">// build LEAD query</span></pre><pre class="alt"><span id="lnum3" class="lnum">   3:</span>   XDocument xDoc = XDocument.Load(<span class="str">@"SalesForceSchema.xml"</span>);</pre><pre class="alteven"><span id="lnum4" class="lnum">   4:</span>   var fields = from x <span class="kwrd">in</span> xDoc.Root.Element(<span class="str">"Lead"</span>).Elements(<span class="str">"Field"</span>) </pre><pre class="alt"><span id="lnum5" class="lnum">   5:</span>                select x.Attribute(<span class="str">"SfName"</span>).Value;</pre><pre class="alteven"><span id="lnum6" class="lnum">   6:</span>   <span class="kwrd">string</span> query = String.Format(<span class="str">"SELECT {0} FROM Lead </span></pre><pre class="alt"><span id="lnum7" class="lnum">   7:</span>                                 WHERE Email = ''"</pre><pre class="alteven"><span id="lnum8" class="lnum">   8:</span>                                , <span class="kwrd">string</span>.Join(<span class="str">","</span>, fields));</pre><pre class="alt"><span id="lnum9" class="lnum">   9:</span>  </pre><pre class="alteven"><span id="lnum10" class="lnum">  10:</span>   <span class="kwrd">string</span> sfQuery = String.Format(<span class="str">"{0}/services/data/v23.0/query?q={1}"</span>,</pre><pre class="alt"><span id="lnum11" class="lnum">  11:</span>                    token.instance_url,</pre><pre class="alteven"><span id="lnum12" class="lnum">  12:</span>                    query);</pre><pre class="alt"><span id="lnum13" class="lnum">  13:</span>   HttpWebRequest request = HttpWebRequest.Create(sfQuery) <span class="kwrd">as</span> HttpWebRequest;</pre><pre class="alteven"><span id="lnum14" class="lnum">  14:</span>   request.Headers.Add(<span class="str">"Authorization"</span>, <span class="str">"OAuth "</span> + token.access_token);</pre><pre class="alt"><span id="lnum15" class="lnum">  15:</span>   request.ContentType = <span class="str">"application/json"</span>;</pre><pre class="alteven"><span id="lnum16" class="lnum">  16:</span>   request.Method = <span class="str">"GET"</span>;</pre><pre class="alt"><span id="lnum17" class="lnum">  17:</span>  </pre><pre class="alteven"><span id="lnum18" class="lnum">  18:</span>   WebResponse webResponse = request.GetResponse();</pre><pre class="alt"><span id="lnum19" class="lnum">  19:</span>   var sr = <span class="kwrd">new</span> System.IO.StreamReader(webResponse.GetResponseStream());</pre><pre class="alteven"><span id="lnum20" class="lnum">  20:</span>   <span class="kwrd">string</span> json = sr.ReadToEnd();</pre><pre class="alt"><span id="lnum21" class="lnum">  21:</span>   var leads = js.Deserialize&lt;sfdcLeadCollection&lt;sfdcLeadForCollection&gt;&gt;</pre><pre class="alteven"><span id="lnum22" class="lnum">  22:</span>                                     (HttpUtility.UrlDecode(json));</pre><pre class="alt"><span id="lnum23" class="lnum">  23:</span> }</pre><pre class="alteven"><span id="lnum24" class="lnum">  24:</span>  </pre><pre class="alt"><span id="lnum25" class="lnum">  25:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> sfdcLeadCollection&lt;T&gt; {</pre><pre class="alteven"><span id="lnum26" class="lnum">  26:</span>   <span class="kwrd">public</span> <span class="kwrd">bool</span> Done { get; set; }</pre><pre class="alt"><span id="lnum27" class="lnum">  27:</span>   <span class="kwrd">public</span> <span class="kwrd">int</span> TotalSize { get; set; }</pre><pre class="alteven"><span id="lnum28" class="lnum">  28:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> nextRecordsUrl { get; set; }</pre><pre class="alt"><span id="lnum29" class="lnum">  29:</span>   <span class="kwrd">public</span> List&lt;T&gt; Records { get; set; }</pre><pre class="alteven"><span id="lnum30" class="lnum">  30:</span> }</pre><pre class="alt"><span id="lnum31" class="lnum">  31:</span>  </pre><pre class="alteven"><span id="lnum32" class="lnum">  32:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> sfdcAttributes {</pre><pre class="alt"><span id="lnum33" class="lnum">  33:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Type { get; set; }</pre><pre class="alteven"><span id="lnum34" class="lnum">  34:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Url { get; set; }</pre><pre class="alt"><span id="lnum35" class="lnum">  35:</span> }</pre><pre class="alteven"><span id="lnum36" class="lnum">  36:</span>  </pre><pre class="alt"><span id="lnum37" class="lnum">  37:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> sfdcLeadForCollection : sObjectLead {</pre><pre class="alteven"><span id="lnum38" class="lnum">  38:</span>   <span class="kwrd">public</span> sfdcAttributes Attributes { get; set; }</pre><pre class="alt"><span id="lnum39" class="lnum">  39:</span> }</pre><pre class="alteven"><span id="lnum40" class="lnum">  40:</span>  </pre><pre class="alt"><span id="lnum41" class="lnum">  41:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> sObjectLead {</pre><pre class="alteven"><span id="lnum42" class="lnum">  42:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Id { get; set; }</pre><pre class="alt"><span id="lnum43" class="lnum">  43:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Email { get; set; }</pre><pre class="alteven"><span id="lnum44" class="lnum">  44:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> FirstName { get; set; }</pre><pre class="alt"><span id="lnum45" class="lnum">  45:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> LastName { get; set; }</pre><pre class="alteven"><span id="lnum46" class="lnum">  46:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Company { get; set; }</pre><pre class="alt"><span id="lnum47" class="lnum">  47:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Phone { get; set; }</pre><pre class="alteven"><span id="lnum48" class="lnum">  48:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> MobilePhone { get; set; }</pre><pre class="alt"><span id="lnum49" class="lnum">  49:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Fax { get; set; }</pre><pre class="alteven"><span id="lnum50" class="lnum">  50:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Website { get; set; }</pre><pre class="alt"><span id="lnum51" class="lnum">  51:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Street { get; set; }</pre><pre class="alteven"><span id="lnum52" class="lnum">  52:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> City { get; set; }</pre><pre class="alt"><span id="lnum53" class="lnum">  53:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> State { get; set; }</pre><pre class="alteven"><span id="lnum54" class="lnum">  54:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> Country { get; set; }</pre><pre class="alt"><span id="lnum55" class="lnum">  55:</span>   <span class="kwrd">public</span> <span class="kwrd">string</span> PostalCode { get; set; }</pre><pre class="alteven"><span id="lnum56" class="lnum">  56:</span> }</pre></div></div>
    <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d4ce2678-9920-4365-b49b-a462e4d1a280" class="wlWriterEditableSmartContent">Technorati Tags: <a href="" rel="tag">salesforce</a>,<a href="" rel="tag">rest api</a></div>
Comments powered by Disqus