function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Surinder BhomraSurinder Bhomra 

Get Dependent Picklist Values Using C# REST API

Within one of my Salesforce object, I have cascading picklists where the selection of one picklist displays values for the next level picklist. So I have three dependent picklists.

What I would like to do within my C# application using the REST API approach is to get back the dependent values based on the object field name and value I pass.

At the moment, my method to do this looks like the following:
public static async Task<List<ObjectFieldPicklistValue>> GetPicklistFieldItems(string objectApiName, string pickListFieldName)
{
    string cacheKey = "{objectApiName}|{pickListFieldName}";

    List<ObjectFieldPicklistValue> pickListValues = CacheEngine.Get<List<ObjectFieldPicklistValue>>(cacheKey);

    if (pickListValues == null)
    {
        Authentication salesforceAuth = await AuthenticationResponse.GetAccessToken();

        HttpClient queryClient = new HttpClient();

        string apiUrl = $"{SalesforceConfig.PlatformUrl}/services/data/v37.0/sobjects/{objectApiName}/describe";

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, apiUrl);
        request.Headers.Add("Authorization", $"Bearer {salesforceAuth.AccessToken}");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await queryClient.SendAsync(request);

        string outputJson = await response.Content.ReadAsStringAsync();

        if (!string.IsNullOrEmpty(outputJson))
        {
            // Get all the fields information from the object.
            ObjectFieldInfo objectField = JsonConvert.DeserializeObject<ObjectFieldInfo>(outputJson);

            // Filter the fields to get the required picklist.
            ObjectField pickListField = objectField.Fields.FirstOrDefault(of => of.Name == pickListFieldName && of.Type == "picklist");

            List<ObjectFieldPicklistValue> picklistItems = pickListField?.PicklistValues.ToList();

            #region Set cache

            pickListValues = picklistItems;

            // Add collection of pick list items to cache.
            CacheEngine.Add(picklistItems, cacheKey, 15);

            #endregion
        }
    }

    return pickListValues;
}
I am getting back the items of a picklist based on the object and field name. From my research online, I can see in the REST request that some of my picklist values have a "validFor" field. But don't exactly understand how to decipher this to get the dependent values.
NagendraNagendra (Salesforce Developers) 
Hi Surinder Bhomra,

There is a good summary of using validFor in get lists of dependent picklist options in Apex(http://salesforce.stackexchange.com/questions/4462/get-lists-of-dependent-picklist-options-in-apex/4876#4876).

In short, the validFor field is a Base64 encoded string where, when read from left to right, each encoded bit indicates if the dependent value is valid for each controlling value.

See the explanation and sample code in About Dependent Picklists(https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_describesobjects_describesobjectresult.htm).

There is additional Apex sample code in Salesforce: Acquiring Dependent Picklists in Apex(http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/)

Kindly mark this post as solved if the information help's so that it gets removed from the unanswered queue and becomes a proper solution which results in helping others who are really in need of it.

Best Regards,
Nagendra.P​
Surinder BhomraSurinder Bhomra
I have managed to almost translate the functionality from this Gist: https://gist.github.com/boxfoot/4166342.

However, I am encountering an issue whereby the first picklist dependent values is getting replicated across all other listings of dependent values. The only thing that could be causing this issue is my TestBit check that I have translated into C#:
public static bool TestBit(string validFor, int pos)
 {
            double byteToCheck = Math.Floor((double)(pos / 8));
            int bit = 7 - (pos % 8);

            try
            {
                return ((int)Math.Pow(2, bit) & validFor[(int)byteToCheck]) >> bit == 1;
            }
            catch
            {
                return false;
            }
}

Everything else is working when pulling out all the values. Just the repitition of the same dependent values from the first pickllist is getting added to the dependent values of other picklist selections.
Andrew FandreAndrew Fandre
I've got a solution. It hasn't been optimized. But I finally figured out how to parse the validFor value from the dependent picklist.The position of the "1"s in the decoded string indicate the index of the controlling picklist that the dependent value is authorized for. I've abstratcted the REST calls, you should be able to figure out those from the example above.
public async Task<string> GetDependentsFromRest(string controllerFieldName, string dependentFieldName)
{

    List<Picklist> controllerList = await GetPicklistFromREST("controllerFieldName");
    List<Picklist> dependentList = await GetPicklistFromREST("dependentFieldName");

    List<DependentPicklist> dpList = new List<DependentPicklist>();
    
    //populate the return list with the controller and the index of the controllerList
    int idx = 0;
    foreach (var controller in controllerList)
    {
        DependentPicklist dp = new DependentPicklist();
        dp.Index = idx;
        dp.Controller = controller.Name;
        dpList.add(dp);
        idx++;
    }
    
    List<DecodedValidFor> decodedValueForList = new List<DecodedValidFor>();
    //populate the dependent list with the decoded validFor
    foreach (var dependent in dependentList)
    {
        DecodedValidFor dcvf = new DecodedValidFor();
        dcvf.Name = dependent.Name;
        dcvf.Decoded = base64ToBits(dependent.validFor);
        decodedValueForList.Add(dcvf);
    }

    //loop over the returnList getting the index of the controlling picklist
    foreach (var controller in dpList)
    {
        DependentPicklist currentPicklist = dpList.SingleOrDefault(dp => dp.Index == controller.Index);

        List<string> dependentList = new List<string>();
        foreach (var dcvf in decodedValueForList)
        {
            for (int i = 0; i < dcvf.Decoded.Length; i++)
            {
                if (dcvf.Decoded[i] == '1')
                {
                    if (i == currentPicklist.Index)
                    {
                        dependentList.Add(dcvf.Name);
                    }
                }
            }
        }
        currentPicklist.Dependents = dependentList;
        
    }

    JavaScriptSerializer serializer = new JavaScriptSerializer();

    return serializer.Serialize(dpList);

}
public static string base64ToBits(string validFor)
{
    string validForBits = "";
    string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    for (int i = 0; i < validFor.Length; i++)
    {
        string thisChar = validFor.Substring(i, 1);
        int val = base64Chars.IndexOf(thisChar);
        string bits = Convert.ToString(val, 2).PadLeft(6, '0');
        validForBits += bits;
    }
    return validForBits;
}
public class DecodedValidFor
{
    public string Name { get; set; }
    public string Decoded { get; set; }
}
public class Picklist
{
    public string Name { get; set; }
    public string validFor { get; set; }
}
public class DependentPicklist
{
    public int Index { get; set; }
    public string Controller { get; set; }
    public List<string> Dependents { get; set; }
}