Force Client

The PerigeeSalesForceClient is an easy to use implementation on top of NetCoreForce that allows you to connect and authorize easily. It manages the token refreshes and local disk persistence as well as provides several additional methods for easy communication to SalesForce.

We have used and implemented custom logic into NetCoreForce. To get more information about it's functionality the client documentation can be found here


There are two ways to authorize and keep the connection automatically active.

  • The Consumer Key and Consumer Secret are from the connected application

  • Username (or password if using UserPass flow) are the login user details

  • If using JWT, you'll supply the Certificate and optional password that was uploaded to the connected application

//Username Password
var client = PerigeeSalesForceClient.UsernamePassword(
consumerKey, consumerSecret, 
user, pass);

var client = PerigeeSalesForceClient.JWT(
consumerKey, consumerSecret, 
user, new X509Certificate2("SF.pfx", "ABCD123"), 

Once connected with either of the two methods mentioned above, you'll have full access to the available commands!

Connected Applications

To get to the connected applications in SalesForce, go to "Setup => Build => Create => Apps"

  1. Under the "Connected Apps" Create or Edit one

  2. Enter a Name and Contact Email

  3. Click the box: Enable OAuth Settings

  4. Enter a Callback Url, something like:

  5. Click Use digital signatures

    1. Upload a certificate (.cer file) (it can be self-signed)

    2. One option for creating a certificate is the Java Key Tool.

    3. Perigee ships with a CertGen as well, code is linked below

  6. Add Selected OAuth Scopes.

    1. An example of these scopes might be:

      1. full

      2. api

      3. refresh_token,offline_access

  7. Click Save

  8. There's a button called: "Manage Consumer Details" - This will show your consumer key and consumer secret. Store them.

  9. Click the "Manage" button at the top of the connected app, and then "Edit policies"

    1. Setup the polices as you need.

    2. An example of this would be:

      1. Permitted Users: "Admin Approved users are pre-authorized"

      2. IP Relaxation: "Relax IP restrictions"

To create a self signed cert that is valid for 5 years using Perigee:

var x5 = CertGen2.SelfSigned();
CertGen2.SaveX509ToPath(x5, "C:\\SF", "SF", "ABCDEFG12345");


Our little demo model class is available here. As you can see, we've used Newtonsoft to remap "Name" to "AccountName".

public class SFAccount
    public string id { get; set; }

    public string AccountName { get; set; }

    public string Type { get; set; }


Describe an SObject

To perform a single describe call:

var res = client.GetObjectDescribe("Account").GetAwaiter().GetResult();

Get Objects

There are a bunch of ways to get objects, including Querying for them. You may also supply direct IDS in a few ways as well:

//Get a single object by ID, mapped back, supplying the fields
SFAccount byID = client.GetObjectById<SFAccount>("Account", "001f400000Mk8lPAAR", new List<string>() { "id", "name" }).GetAwaiter().GetResult();

//Get a list of objects by ID, dynamically automapped from your class to SalesForce
List<SFAccount> objectsByID = client.GetObjectsAsync<SFAccount>("Account", new List<string>() { "001f400000Mk8lPAAR", "001f400001N4NXqAAN" }).GetAwaiter().GetResult();

If you're going to be calling the auto-mapped version frequently, please cache the map results and supply them to the GetObjectsAsync call as shown:

//Store the cache somewhere static
var CachedProperties = client.MapProperties<SFAccount>("Account").Values.ToList();

//Supply cache map on frequent and subsequent calls
List<SFAccount> objectsByID = client.GetObjectsAsync<SFAccount>("Account", new List<string>() { "001f400000Mk8lPAAR", "001f400001N4NXqAAN" }, CachedProperties).GetAwaiter().GetResult();

Watch for changes

We provide an asynchronous block that automatically does all the date time handling, offsets, delays, authentication paramaters, etc. You can easily start or stop this process and it will pick up from the last set of records that were sent through.

client.WatchAsync<SFAccount>("Account", CTS.Token, (ct, updated, deleted) => {
    //updated records, bound back to an SFAccount class
    foreach (var item in updated) { 
        Console.WriteLine($"[{}] {item.AccountName}({item.Type})"); }
    //Deleted ID's, along with the deleted date
    foreach (var item in deleted) { 
        Console.WriteLine($"{} - {item.deletedDate:G}"); }

Helper watch method

To add a watch directly from Perigee Startup as a Managed Thread:

PerigeeApplication.ApplicationNoInit("SalesForce Demo", (c) => {

    c.AddSalesForceWatch<SFAccount>("WatchAccounts", "Account", cKey, cSec, sUser, x5092Cert, "login", 
    (ct, log, updated, deleted) => {

        //updated records, bound back to an SFAccount class
        foreach (var item in updated)
            Console.WriteLine($"[{}] {item.AccountName}({item.Type})");

        //Deleted ID's, along with the deleted date
        foreach (var item in deleted)
            Console.WriteLine($"{} - {item.deletedDate:G}");



Make sure to configure your own:

  • Certificate

  • Consumer key

  • Consumer secret

  • User

  • Domain

See the Authorization section above

Update a record

There are two easy ways to update a single record

//Update by bound object properties, serialized through newtonsoft
client.UpdateRecord<SFAccount>("Account", "001f400000Mk8lPAAR", new SFAccount() { Type = "Prospect" }).GetAwaiter().GetResult();

//Supply a dyanamic object or class, unbound
client.UpdatePatch("Account", "001f400000Mk8lPAAR", new { Rating = "Warm" }).GetAwaiter().GetResult();

Query + SOQL

To execute a query, simply supply the query along with a class to map back to:

var accounts = client.Query<SFAccount>("SELECT id,name from account limit 10").GetAwaiter().GetResult();

Many other methods

For the full list of methods and other ways of working with SalesForce, please visit the GitHub page!

Last updated