public static void Main()
        {
            Console.Title = "Function and Actions demonstration";

            // Track entity instance URIs so those records can be deleted prior to exit.
            Dictionary <string, Uri> entityUris = new Dictionary <string, Uri>();

            try
            {
                // Get environment configuration information from the connection string in App.config.
                ServiceConfig config = new ServiceConfig(
                    ConfigurationManager.ConnectionStrings["Connect"].ConnectionString);

                // Use the service class that handles HTTP messaging, error handling, and
                // performance optimizations.
                using (CDSWebApiService svc = new CDSWebApiService(config))
                {
                    // Create any entity instances required by the program code that follows
                    CreateRequiredRecords(svc, entityUris);

                    #region Call an unbound function with no parameters
                    Console.WriteLine("\n* Call an unbound function with no parameters.");

                    // Retrieve the current user's full name from the WhoAmI function:
                    Console.Write("\tGetting information on the current user..");
                    JToken currentUser = svc.Get("WhoAmI");

                    // Obtain the user's ID and full name
                    JToken user = svc.Get("systemusers(" + currentUser["UserId"] + ")?$select=fullname");

                    Console.WriteLine("completed.");
                    Console.WriteLine("\tCurrent user's full name is '{0}'.", user["fullname"]);
                    #endregion Call an unbound function with no parameters

                    #region Call an unbound function that requires parameters
                    Console.WriteLine("\n* Call an unbound function that requires parameters");

                    // Retrieve the code for the specified time zone
                    int    localeID     = 1033;
                    string timeZoneName = "Pacific Standard Time";

                    // Define the unbound function and its parameters
                    string[] uria = new string[] {
                        "GetTimeZoneCodeByLocalizedName",
                        "(LocalizedStandardName=@p1,LocaleId=@p2)",
                        "?@p1='" + timeZoneName + "'&@p2=" + localeID
                    };

                    // This would also work:
                    // string[] uria = ["GetTimeZoneCodeByLocalizedName", "(LocalizedStandardName='" +
                    //    timeZoneName + "',LocaleId=" + localeId + ")"];

                    JToken localizedName = svc.Get(string.Join("", uria));
                    string timeZoneCode  = localizedName["TimeZoneCode"].ToString();

                    Console.WriteLine(
                        "\tThe time zone '{0}' has the code '{1}'.", timeZoneName, timeZoneCode);
                    #endregion Call an unbound function that requires parameters

                    #region Call a bound function
                    Console.WriteLine("\n* Call a bound function");

                    // Retrieve the total time (minutes) spent on all tasks associated with
                    // incident "Sample Case".
                    string boundUri = entityUris["Sample Case"] +
                                      @"/Microsoft.Dynamics.CRM.CalculateTotalTimeIncident()";

                    JToken cttir     = svc.Get(boundUri);
                    string totalTime = cttir["TotalTime"].ToString();

                    Console.WriteLine("\tThe total duration of tasks associated with the incident " +
                                      "is {0} minutes.", totalTime);
                    #endregion Call a bound function

                    #region Call an unbound action that requires parameters
                    Console.WriteLine("\n* Call an unbound action that requires parameters");

                    // Close the existing opportunity "Opportunity to win" and mark it as won.
                    JObject opportClose = new JObject()
                    {
                        { "subject", "Won Opportunity" },
                        { "*****@*****.**", entityUris["Opportunity to win"] }
                    };

                    JObject winOpportParams = new JObject()
                    {
                        { "Status", "3" },
                        { "OpportunityClose", opportClose }
                    };

                    JObject won = svc.Post("WinOpportunity", winOpportParams);

                    Console.WriteLine("\tOpportunity won.");
                    #endregion Call an unbound action that requires parameters

                    #region Call a bound action that requires parameters
                    Console.WriteLine("\n* Call a bound action that requires parameters");

                    // Add a new letter tracking activity to the current user's queue.
                    // First create a letter tracking instance.
                    JObject letterAttributes = new JObject()
                    {
                        { "subject", "Example letter" },
                        { "description", "Body of the letter" }
                    };

                    Console.Write("\tCreating letter 'Example letter'..");

                    Uri letterUri = svc.PostCreate("letters", letterAttributes);
                    entityUris.Add("Example letter", letterUri);

                    Console.WriteLine("completed.");

                    //Retrieve the ID associated with this new letter tracking activity.
                    JToken letter           = svc.Get(letterUri + "?$select=activityid,subject");
                    string letterActivityId = (string)letter["activityid"];

                    // Retrieve the URL to current user's queue.
                    string myUserId = (string)currentUser["UserId"];

                    JToken queueRef   = svc.Get("systemusers(" + myUserId + ")/queueid/$ref");
                    string myQueueUri = (string)queueRef["@odata.id"];

                    //Add the letter activity to current user's queue, then return its queue ID.
                    JObject targetUri = JObject.Parse(
                        @"{activityid: '" + letterActivityId + @"', '@odata.type': 'Microsoft.Dynamics.CRM.letter' }");

                    JObject addToQueueParams = new JObject()
                    {
                        { "Target", targetUri }
                    };

                    string queueItemId = (string)svc.Post(
                        myQueueUri + "/Microsoft.Dynamics.CRM.AddToQueue", addToQueueParams)["QueueItemId"];

                    Console.WriteLine("\tLetter 'Example letter' added to current user's queue.");
                    Console.WriteLine("\tQueueItemId returned from AddToQueue action: {0}", queueItemId);
                    #endregion Call a bound action that requires parameters

                    #region Call a bound custom action that requires parameters
                    Console.WriteLine("\n* Call a bound custom action that requires parameters");

                    // Add a note to a specified contact. Uses the custom action sample_AddNoteToContact, which
                    // is bound to the contact to annotate, and takes a single param, the note to add. It also
                    // returns the URI to the new annotation.

                    JObject note = JObject.Parse(
                        @"{NoteTitle: 'Sample note', NoteText: 'The text content of the note.'}");
                    string actionUri = entityUris["Jon Fogg"].ToString() + "/Microsoft.Dynamics.CRM.sample_AddNoteToContact";

                    JObject contact       = svc.Post(actionUri, note);
                    Uri     annotationUri = new Uri(svc.BaseAddress + "annotations(" + contact["annotationid"] + ")");
                    entityUris.Add((string)note["NoteTitle"], annotationUri);

                    Console.WriteLine("\tA note with the title '{0}' was created and " +
                                      "associated with the contact 'Jon Fogg'.", note["NoteTitle"]);
                    #endregion Call a bound custom action that requires parameters

                    #region Call an unbound custom action that requires parameters
                    Console.WriteLine("\n* Call an unbound custom action that requires parameters");

                    // Create a customer of the specified type, using the custom action sample_CreateCustomer,
                    // which takes two parameters: the type of customer ('account' or 'contact') and the name of
                    // the new customer.
                    string  customerName       = "New account customer (sample)";
                    JObject customerAttributes = JObject.Parse(
                        @"{CustomerType: 'account', AccountName: '" + customerName + "'}");

                    JObject response = svc.Post("sample_CreateCustomer", customerAttributes);
                    Console.WriteLine("\tThe account '" + customerName + "' was created.");

                    // Because the CreateCustomer custom action does not return any data about the created instance,
                    // we must query the customer instance to figure out its URI.
                    JToken customer    = svc.Get("accounts?$filter=name eq 'New account customer (sample)'&$select=accountid&$top=1");
                    Uri    customerUri = new Uri(svc.BaseAddress + "accounts(" + customer["value"][0]["accountid"] + ")");
                    entityUris.Add(customerName, customerUri);

                    // Try to call the same custom action with invalid parameters, here the same name is
                    // not valid for a contact. (ContactFirstname and ContactLastName parameters are
                    // required when CustomerType is contact.
                    customerAttributes = JObject.Parse(
                        @"{CustomerType: 'contact', AccountName: '" + customerName + "'}");

                    try
                    {
                        customerUri = svc.PostCreate("sample_CreateCustomer", customerAttributes);
                        Console.WriteLine("\tCall to the custom CreateCustomer action succeeded, which was not expected.");
                    }
                    catch (ServiceException e)
                    {
                        Console.WriteLine("\tCall to the custom CreateCustomer action did not succeed (as was expected).");
                        Console.WriteLine($"\t\tError: {e.Message}");
                    }
                    #endregion Call an unbound custom action that requires parameters

                    DeleteEntityRecords(svc, entityUris);
                }
            }
            catch (Exception e)
            {
                Console.BackgroundColor = ConsoleColor.Red; // Highlight exceptions
                if (e is AggregateException)
                {
                    foreach (Exception inner in (e as AggregateException).InnerExceptions)
                    {
                        Console.WriteLine("\n" + inner.Message);
                    }
                }
                else if (e is ServiceException)
                {
                    var ex = e as ServiceException;
                    Console.WriteLine("\nMessage send response: status code {0}, {1}",
                                      ex.StatusCode, ex.ReasonPhrase);
                }
                Console.ReadKey(); // Pause terminal
            }
        }
        static void Main()
        {
            //List of Uris for records created in this sample
            List <Uri> entityUris           = new List <Uri>();
            bool       deleteCreatedRecords = true;

            try
            {
                using (CDSWebApiService svc = new CDSWebApiService(config))
                {
                    Console.WriteLine("--Starting Basic Operations--");

                    #region Section 1: Basic Create and Update operations
                    Console.WriteLine("--Section 1 started--");
                    //Create a contact
                    var contact1 = new JObject
                    {
                        { "firstname", "Rafel" },
                        { "lastname", "Shillo" }
                    };
                    Uri contact1Uri = svc.PostCreate("contacts", contact1);
                    Console.WriteLine($"Contact '{contact1["firstname"]} " +
                                      $"{contact1["lastname"]}' created.");
                    entityUris.Add(contact1Uri); //To delete later
                    Console.WriteLine($"Contact URI: {contact1Uri}");

                    //Update a contact
                    JObject contact1Add = new JObject
                    {
                        { "annualincome", 80000 },
                        { "jobtitle", "Junior Developer" }
                    };
                    svc.Patch(contact1Uri, contact1Add);
                    Console.WriteLine(
                        $"Contact '{contact1["firstname"]} {contact1["lastname"]}' " +
                        $"updated with jobtitle and annual income");

                    //Retrieve a contact
                    var retrievedcontact1 = svc.Get(contact1Uri.ToString() +
                                                    "?$select=fullname,annualincome,jobtitle,description");
                    Console.WriteLine($"Contact '{retrievedcontact1["fullname"]}' retrieved: \n" +
                                      $"\tAnnual income: {retrievedcontact1["annualincome"]}\n" +
                                      $"\tJob title: {retrievedcontact1["jobtitle"]} \n" +
                                      //description is initialized empty.
                                      $"\tDescription: {retrievedcontact1["description"]}.");

                    //Modify specific properties and then update entity instance.
                    JObject contact1Update = new JObject
                    {
                        { "jobtitle", "Senior Developer" },
                        { "annualincome", 95000 },
                        { "description", "Assignment to-be-determined" }
                    };
                    svc.Patch(contact1Uri, contact1Update);

                    Console.WriteLine($"Contact '{retrievedcontact1["fullname"]}' updated:\n" +
                                      $"\tJob title: {contact1Update["jobtitle"]}\n" +
                                      $"\tAnnual income: {contact1Update["annualincome"]}\n" +
                                      $"\tDescription: {contact1Update["description"]}\n");

                    // Change just one property
                    string telephone1 = "555-0105";
                    svc.Put(contact1Uri.ToString(), "telephone1", telephone1);
                    Console.WriteLine($"Contact '{retrievedcontact1["fullname"]}' " +
                                      $"phone number updated.");

                    //Now retrieve just the single property.
                    var telephone1Value = svc.Get($"{contact1Uri}/telephone1");
                    Console.WriteLine($"Contact's telephone # is: {telephone1Value["value"]}.");

                    #endregion Section 1: Basic Create and Update operations

                    #region Section 2: Create record associated to another
                    /// <summary>
                    /// Demonstrates creation of entity instance and simultaneous association to another,
                    ///  existing entity.
                    /// </summary>
                    ///

                    Console.WriteLine("\n--Section 2 started--");


                    //Create a new account and associate with existing contact in one operation.
                    var account1 = new JObject
                    {
                        { "name", "Contoso Ltd" },
                        { "telephone1", "555-5555" },
                        { "*****@*****.**", contact1Uri }
                    };
                    var account1Uri = svc.PostCreate("accounts", account1);
                    entityUris.Add(account1Uri); //To delete later
                    Console.WriteLine($"Account '{account1["name"]}' created.");
                    Console.WriteLine($"Account URI: {account1Uri}");
                    //Retrieve account name and primary contact info
                    JObject retrievedAccount1 = svc.Get($"{account1Uri}?$select=name," +
                                                        $"&$expand=primarycontactid($select=fullname,jobtitle,annualincome)") as JObject;

                    Console.WriteLine($"Account '{retrievedAccount1["name"]}' has primary contact " +
                                      $"'{retrievedAccount1["primarycontactid"]["fullname"]}':");
                    Console.WriteLine($"\tJob title: {retrievedAccount1["primarycontactid"]["jobtitle"]} \n" +
                                      $"\tAnnual income: {retrievedAccount1["primarycontactid"]["annualincome"]}");

                    #endregion Section 2: Create record associated to another

                    #region Section 3: Create related entities
                    /// <summary>
                    /// Demonstrates creation of entity instance and related entities in a single operation.
                    /// </summary>
                    ///
                    Console.WriteLine("\n--Section 3 started--");
                    //Create the following entries in one operation: an account, its
                    // associated primary contact, and open tasks for that contact.  These
                    // entity types have the following relationships:
                    //    Accounts
                    //       |---[Primary] Contact (N-to-1)
                    //              |---Tasks (1-to-N)

                    //Build the Account object inside-out, starting with most nested type(s)
                    JArray  tasks = new JArray();
                    JObject task1 = new JObject
                    {
                        { "subject", "Sign invoice" },
                        { "description", "Invoice #12321" },
                        { "scheduledend", DateTimeOffset.Parse("4/19/2019") }
                    };
                    tasks.Add(task1);
                    JObject task2 = new JObject
                    {
                        { "subject", "Setup new display" },
                        { "description", "Theme is - Spring is in the air" },
                        { "scheduledstart", DateTimeOffset.Parse("4/20/2019") }
                    };
                    tasks.Add(task2);
                    JObject task3 = new JObject
                    {
                        { "subject", "Conduct training" },
                        { "description", "Train team on making our new blended coffee" },
                        { "scheduledstart", DateTimeOffset.Parse("6/1/2019") }
                    };
                    tasks.Add(task3);

                    JObject contact2 = new JObject
                    {
                        { "firstname", "Susie" },
                        { "lastname", "Curtis" },
                        { "jobtitle", "Coffee Master" },
                        { "annualincome", 48000 },
                        //Add related tasks using corresponding navigation property
                        { "Contact_Tasks", tasks }
                    };

                    JObject account2 = new JObject
                    {
                        { "name", "Fourth Coffee" },
                        //Add related contacts using corresponding navigation property
                        { "primarycontactid", contact2 }
                    };

                    //Create the account and related records
                    Uri account2Uri = svc.PostCreate("accounts", account2);
                    Console.WriteLine($"Account '{account2["name"]}  created.");
                    entityUris.Add(account2Uri); //To delete later
                    Console.WriteLine($"Contact URI: {account2Uri}");

                    //Retrieve account, primary contact info, and assigned tasks for contact.
                    //CDS only supports querying-by-expansion one level deep, so first query
                    // account-primary contact.
                    var retrievedAccount2 = svc.Get($"{account2Uri}?$select=name," +
                                                    $"&$expand=primarycontactid($select=fullname,jobtitle,annualincome)");

                    Console.WriteLine($"Account '{retrievedAccount2["name"]}' " +
                                      $"has primary contact '{retrievedAccount2["primarycontactid"]["fullname"]}':");

                    Console.WriteLine($"\tJob title: {retrievedAccount2["primarycontactid"]["jobtitle"]} \n" +
                                      $"\tAnnual income: {retrievedAccount2["primarycontactid"]["annualincome"]}");

                    //Next retrieve same contact and its assigned tasks.
                    //Don't have a saved URI for contact 'Susie Curtis', so create one
                    // from base address and entity ID (and add it to collection for cleanup).
                    Uri contact2Uri = new Uri($"{svc.BaseAddress}contacts({retrievedAccount2["primarycontactid"]["contactid"]})");
                    entityUris.Add(contact2Uri); //To delete later
                    //Retrieve the contact
                    var retrievedcontact2 = svc.Get($"{contact2Uri}?$select=fullname," +
                                                    $"&$expand=Contact_Tasks($select=subject,description,scheduledstart,scheduledend)");

                    Console.WriteLine($"Contact '{retrievedcontact2["fullname"]}' has the following assigned tasks:");
                    foreach (JToken tk in retrievedcontact2["Contact_Tasks"])
                    {
                        Console.WriteLine(
                            $"Subject: {tk["subject"]}, \n" +
                            $"\tDescription: {tk["description"]}\n" +
                            $"\tStart: {tk["scheduledstart"].Value<DateTime>():d}\n" +
                            $"\tEnd: {tk["scheduledend"].Value<DateTime>():d}\n");
                    }
                    #endregion Section 3: Create related entities

                    #region Section 4: Associate and Disassociate entities
                    /// <summary>
                    /// Demonstrates associating and disassociating of existing entity instances.
                    /// </summary>
                    Console.WriteLine("\n--Section 4 started--");
                    //Add 'Rafel Shillo' to the contact list of 'Fourth Coffee',
                    // a 1-to-N relationship.
                    JObject rel1 = new JObject
                    {
                        { "@odata.id", contact1Uri }
                    }; //relationship object for msg content
                    Uri navUri1 = new Uri($"{account2Uri}/contact_customer_accounts/$ref");
                    //Create relationship
                    svc.Post(navUri1.ToString(), rel1);
                    Console.WriteLine($"Contact '{retrievedcontact1["fullname"]}' " +
                                      $"associated to account '{account2["name"]}'.");

                    //Retrieve and output all contacts for account 'Fourth Coffee'.
                    var retrievedContactList1 = svc.Get($"{account2Uri}/contact_customer_accounts?" +
                                                        $"$select=fullname,jobtitle");

                    Console.WriteLine($"Contact list for account '{retrievedAccount2["name"]}':");

                    foreach (JToken ct in retrievedContactList1["value"])
                    {
                        Console.WriteLine($"\tName: {ct["fullname"]}, Job title: {ct["jobtitle"]}");
                    }

                    //Dissociate the contact from the account.  For a collection-valued
                    // navigation property, must append URI of referenced entity.
                    var dis1Uri = $"{navUri1}?$id={contact1Uri}";
                    //Equivalently, could have dissociated from the other end of the
                    // relationship, using the single-valued navigation ref, located in
                    // the contact 'Peter Cambel'.  This dissociation URI has a simpler form:
                    // [Org URI]/api/data/v9.1/contacts([contactid#])/parentcustomerid_account/$ref

                    svc.Delete(dis1Uri);
                    //'Rafel Shillo' was removed from the the contact list of 'Fourth Coffee'

                    //Associate an opportunity to a competitor, an N-to-N relationship.
                    //First, create the required entity instances.
                    JObject comp1 = new JObject
                    {
                        { "name", "Adventure Works" },
                        {
                            "strengths",
                            "Strong promoter of private tours for multi-day outdoor adventures"
                        }
                    };
                    Uri comp1Uri = svc.PostCreate("competitors", comp1);
                    entityUris.Add(comp1Uri); //To delete later

                    JObject oppor1 = new JObject
                    {
                        ["name"]        = "River rafting adventure",
                        ["description"] = "Sales team on a river-rafting offsite and team building"
                    };
                    Uri oppor1Uri = svc.PostCreate("opportunities", oppor1);
                    entityUris.Add(oppor1Uri); //To delete later

                    //Associate opportunity to competitor via opportunitycompetitors_association.
                    // navigation property.
                    JObject rel2 = new JObject
                    {
                        { "@odata.id", comp1Uri }
                    };
                    Uri navUri2 = new Uri($"{oppor1Uri}/opportunitycompetitors_association/$ref");

                    svc.Post(navUri2.ToString(), rel2);
                    Console.WriteLine($"Opportunity '{oppor1["name"]}' associated with competitor '{comp1["name"]}'.");

                    //Retrieve all opportunities for competitor 'Adventure Works'.
                    var retrievedOpporList1 = svc.Get($"{comp1Uri}?$select=name,&$expand=opportunitycompetitors_association($select=name,description)");

                    Console.WriteLine($"Competitor '{retrievedOpporList1["name"]}' has the following opportunities:");
                    foreach (JToken op in
                             retrievedOpporList1["opportunitycompetitors_association"])
                    {
                        Console.WriteLine($"\tName: {op["name"]}, \n" +
                                          $"\tDescription: {op["description"]}");
                    }

                    //Dissociate opportunity from competitor.
                    svc.Delete($"{navUri2}?$id={comp1Uri}");
                    // 'River rafting adventure' opportunity disassociated with 'Adventure Works' competitor

                    #endregion Section 4: Associate and Disassociate entities

                    #region Section 5: Delete sample entities
                    Console.WriteLine("\n--Section 5 started--");
                    //Delete all the created sample entities.  Note that explicit deletion is not required
                    // for contact tasks because these are automatically cascade-deleted with owner.

                    if (!deleteCreatedRecords)
                    {
                        Console.Write("\nDo you want these entity records deleted? (y/n) [y]: ");
                        String answer = Console.ReadLine();
                        answer = answer.Trim();
                        if (!(answer.StartsWith("y") || answer.StartsWith("Y") || answer == string.Empty))
                        {
                            entityUris.Clear();
                        }
                        else
                        {
                            Console.WriteLine("\nDeleting created records.");
                        }
                    }
                    else
                    {
                        Console.WriteLine("\nDeleting created records.");
                    }

                    foreach (Uri entityUrl in entityUris)
                    {
                        svc.Delete(entityUrl.ToString());
                    }
                    #endregion Section 5: Delete sample entities

                    Console.WriteLine("--Basic Operations Completed--");
                    Console.WriteLine("Press any key to close");
                    Console.ReadLine();
                }
            }
            catch (Exception)
            {
                throw;
            }
        }