├── .gitignore ├── README.md ├── SfQuery.sln └── SfQuery ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── SalesforceClient.cs ├── SfQuery.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/SfQuery/v14/.suo 2 | bin/ 3 | obj/ 4 | packages/ 5 | SfQuery/App.config -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SfQuery 2 | 3 | .Net-based command-line utility to query Salesforce data. 4 | 5 | This is mostly a proof of concept on how to integrate with Salesforce's REST API, but it still can be used to query data in the org. 6 | 7 | ## Introduction 8 | 9 | SFQuery uses the Salesforce REST API to perform SOQL queries based the data in your organisation. 10 | 11 | ## Setup 12 | 13 | You will need to create a Connected App endpoint in your org for SFQuery to be able to log onto it. 14 | 15 | You will then need to configure your credentials (username/password/connected app ID and secret) in the App.config file. 16 | 17 | Step-by-step information to be found [here](https://blog.mkorman.uk/integrating-net-and-salesforce-part-1-rest-api/). 18 | 19 | ## Usage 20 | 21 | 22 | ### Querying the data in your org 23 | 24 | To run a query: 25 | 26 | `SfQuery ` 27 | 28 | For instance: 29 | 30 | `SfQuery "Select ID, Name from Contact"` 31 | -------------------------------------------------------------------------------- /SfQuery.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SfQuery", "SfQuery\SfQuery.csproj", "{89D56C84-36F5-474D-90D1-7B9325137F24}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {89D56C84-36F5-474D-90D1-7B9325137F24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {89D56C84-36F5-474D-90D1-7B9325137F24}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {89D56C84-36F5-474D-90D1-7B9325137F24}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {89D56C84-36F5-474D-90D1-7B9325137F24}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /SfQuery/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SfQuery/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | 4 | namespace SfQuery 5 | { 6 | public class Program 7 | { 8 | private static SalesforceClient CreateClient() 9 | { 10 | return new SalesforceClient 11 | { 12 | Username = ConfigurationManager.AppSettings["username"], 13 | Password = ConfigurationManager.AppSettings["password"], 14 | Token = ConfigurationManager.AppSettings["token"], 15 | ClientId = ConfigurationManager.AppSettings["clientId"], 16 | ClientSecret = ConfigurationManager.AppSettings["clientSecret"] 17 | }; 18 | } 19 | 20 | static void Main(string[] args) 21 | { 22 | var client = CreateClient(); 23 | 24 | if (args.Length > 0) 25 | { 26 | client.Login(); 27 | Console.WriteLine(client.Query(args[0])); 28 | } 29 | else 30 | { 31 | client.Login(); 32 | Console.WriteLine(client.Describe("Account")); 33 | Console.WriteLine(client.Describe("Contact")); 34 | Console.WriteLine(client.QueryEndpoints()); 35 | Console.WriteLine(client.Query("SELECT Name from Contact")); 36 | } 37 | Console.ReadLine(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SfQuery/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SfQuery")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("SfQuery")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("89d56c84-36f5-474d-90d1-7b9325137f24")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /SfQuery/SalesforceClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Net.Http.Headers; 6 | using Newtonsoft.Json; 7 | 8 | namespace SfQuery 9 | { 10 | public class SalesforceClient 11 | { 12 | private const string LOGIN_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"; 13 | private const string API_ENDPOINT = "/services/data/v36.0/"; 14 | 15 | public string Username { get; set; } 16 | public string Password { get; set; } 17 | public string Token { get; set; } 18 | public string ClientId { get; set; } 19 | public string ClientSecret { get; set; } 20 | public string AuthToken { get; set; } 21 | public string InstanceUrl { get; set; } 22 | 23 | static SalesforceClient() 24 | { 25 | // SF requires TLS 1.1 or 1.2 26 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; 27 | } 28 | 29 | // TODO: use RestSharps 30 | public void Login() 31 | { 32 | String jsonResponse; 33 | using (var client = new HttpClient()) 34 | { 35 | var request = new FormUrlEncodedContent(new Dictionary 36 | { 37 | {"grant_type", "password"}, 38 | {"client_id", ClientId}, 39 | {"client_secret", ClientSecret}, 40 | {"username", Username}, 41 | {"password", Password + Token} 42 | } 43 | ); 44 | request.Headers.Add("X-PrettyPrint", "1"); 45 | var response = client.PostAsync(LOGIN_ENDPOINT, request).Result; 46 | jsonResponse = response.Content.ReadAsStringAsync().Result; 47 | } 48 | Console.WriteLine($"Response: {jsonResponse}"); 49 | var values = JsonConvert.DeserializeObject>(jsonResponse); 50 | AuthToken = values["access_token"]; 51 | InstanceUrl = values["instance_url"]; 52 | } 53 | 54 | public string QueryEndpoints() 55 | { 56 | using (var client = new HttpClient()) 57 | { 58 | string restQuery = InstanceUrl + API_ENDPOINT; 59 | var request = new HttpRequestMessage(HttpMethod.Get, restQuery); 60 | request.Headers.Add("Authorization", "Bearer " + AuthToken); 61 | request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 62 | request.Headers.Add("X-PrettyPrint", "1"); 63 | var response = client.SendAsync(request).Result; 64 | return response.Content.ReadAsStringAsync().Result; 65 | } 66 | } 67 | 68 | public string Describe(string sObject) 69 | { 70 | using (var client = new HttpClient()) 71 | { 72 | string restQuery = InstanceUrl + API_ENDPOINT + "sobjects/" + sObject; 73 | var request = new HttpRequestMessage(HttpMethod.Get, restQuery); 74 | request.Headers.Add("Authorization", "Bearer " + AuthToken); 75 | request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 76 | request.Headers.Add("X-PrettyPrint", "1"); 77 | var response = client.SendAsync(request).Result; 78 | return response.Content.ReadAsStringAsync().Result; 79 | } 80 | } 81 | 82 | public string Query (string soqlQuery) 83 | { 84 | using (var client = new HttpClient()) 85 | { 86 | string restRequest = InstanceUrl + API_ENDPOINT + "query/?q=" + soqlQuery; 87 | var request = new HttpRequestMessage(HttpMethod.Get, restRequest); 88 | request.Headers.Add("Authorization", "Bearer " + AuthToken); 89 | request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 90 | request.Headers.Add("X-PrettyPrint", "1"); 91 | var response = client.SendAsync(request).Result; 92 | return response.Content.ReadAsStringAsync().Result; 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SfQuery/SfQuery.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {89D56C84-36F5-474D-90D1-7B9325137F24} 8 | Exe 9 | Properties 10 | SfQuery 11 | SfQuery 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /SfQuery/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------