Web API 機能およびアクションのサンプル (C#)

 

公開日: 2017年1月

対象: Dynamics 365 (online)、Dynamics 365 (on-premises)、Dynamics CRM 2016、Dynamics CRM Online

このサンプルは、バインドされた関数とバインドされていない関数およびアクションを実行する方法を示します。このアクションには、Dynamics 365 Web API を使用するカスタム アクションが含まれます。

注意

このサンプルでは、Web API 機能およびアクションのサンプル で説明した操作を提供し、Web API のサンプル (C#) で説明した共通のクライアント側の C# 構造を使用します。

このトピックの内容

前提条件

このサンプルの実行

コード一覧

前提条件

すべての Dynamics 365 Web API C# サンプルの前提条件は、親トピック、Web API のサンプル (C#)Configuration requise セクションで説明されています。

このサンプルの実行

最初に、Microsoft CRM Web API Functions and Actions Sample (C#) に移動し、サンプル アーカイブ ファイル Microsoft CRM Web API Functions and Actions Sample (CS).zip をダウンロードし、その内容をローカル フォルダに抽出します。 このフォルダには、次のファイルが含まれている必要があります。

ファイル

目的/説明

Program.cs

このサンプルのプライマリ ソース コードが含まれます。

App.config

プレースホルダー Dynamics 365 サーバー接続情報を含むアプリケーション構成ファイルです。

Authentication.cs
Configuration.cs
Exceptions.cs

[Web API Helper Code] フォルダーにあるこれらのファイルは、Microsoft Dynamics 365 Web API Helper Library (C#) の使用 に説明されている補足ライブラリを構成しています。

FunctionsAndActions.sln
FunctionsAndActions.csproj
Packages.config
AssemblyInfo.cs

このサンプルの標準 Microsoft Visual Studio 2015 ソリューション、プロジェクト、NuGet パッケージ構成、およびアセンブリ情報ファイルです。

WebAPIFunctionsandActions_1_0_0_0_managed.zip

このサンプルによって追加された 2 つのカスタム アクションを含むカスタム管理ソリューション。

次に、以下の手順を使用して、このサンプルを実行します。

  1. ソリューション ファイル [FunctionsAndActions.sln] を探しダブル クリックして、ソリューションを Visual Studio に読み込みます。 [FunctionsAndActions] ソリューションを構築します。 これにより、見あたらないまたはアップグレードする必要がある必要なすべての NuGet パッケージは自動的にダウンロードされ、インストールされます。

  2. アプリケーション構成ファイル、App.config を編集し、Dynamics 365 サーバーに接続情報を指定します。 詳細については、「Web API Helper code: 構成クラス」を参照してください。

  3. Visual Studio 内から [FunctionsAndActions] プロジェクトを実行します。 すべてのサンプル ソリューションは、既定では、デバッグ モードで実行するように構成されています。

コード一覧

このファイルの最新のソースはサンプル ダウンロード パッケージにあります。

Program.cs

using Microsoft.Crm.Sdk.Samples.HelperCode;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Linq;
using System.Net;

namespace Microsoft.Crm.Sdk.Samples
{
    /// <summary> This program demonstrates calling bound and unbound
    /// functions and actions using the CRM Web API. </summary>
    /// <remarks>
    /// The following standard CRM Web API functions and actions are invoked:
    /// - WhoAmI, a basic unbound function
    /// - GetTimeZoneCodeByLocalizedName, an unbound function that requires parameters
    /// - CalculateTotalTimeIncident, a bound function
    /// - WinOpportunity, an unbound action that takes parameters
    /// - AddToQueue, a bound action that takes parameters
    /// In addition, a managed solution is loaded and custom bound and an unbound actions 
    /// contained within are invoked. 
    /// 
    /// TODO: Before building this application, you must first modify the following  
    /// configuration information in the app.config file:
    ///   - All deployments: Provide connection string service URL's for your organization.
    ///   - CRM (online): Replace the app settings with the correct values for your Azure 
    ///                 application registration. 
    /// See the provided app.config file for more information. 
    /// </remarks>
    class FunctionsAndActions
    {
        //Provides a persistent client-to-CRM server communication channel.
        HttpClient httpClient;
        //Associated solution package that contains custom actions used by this sample
        const string customSolutionFilename = "WebAPIFunctionsandActions_1_0_0_0_managed.zip";
        const string customSolutionName = "WebAPIFunctionsandActions";
        string customSolutionID = null;
        //Centralized collection of entity URIs used to manage lifetimes
        List<string> entityUris = new List<string>();
        //A set of variables to hold the state of and URIs for primary entity instances.
        string incident1Uri, opportunity1Uri, contact1Uri;
        //Objects associated with created URIs, where required.
        JObject contact1;
        Guid myUserId;  //CRM User ID for current user.

        /// <summary> Principal sample code that demonstrates calling bound and unbound functions 
        ///  and actions.</summary>
        public async Task RunAsync()
        {
            HttpResponseMessage response = null;

            #region Call an unbound function with no parameters.
            //Retrieve the current user's full name from the WhoAmI function:
            // https://msdn.microsoft.com/library/mt607925.aspx, which returns a WhoAmIResponse 
            // complex type: https://msdn.microsoft.com/library/mt607982.aspx.
            string currentUser;
            Console.WriteLine("Unbound function: WhoAmI");
            response = await httpClient.GetAsync("WhoAmI", HttpCompletionOption.ResponseContentRead);
            if (!response.IsSuccessStatusCode)
            { throw new CrmHttpResponseException(response.Content); }
            JObject whoAmIresp = JsonConvert.DeserializeObject<JObject>(await
                response.Content.ReadAsStringAsync());
            //First obtain the user's ID.
            myUserId = (Guid)whoAmIresp["UserId"];
            //Then retrieve the full name for that unique ID.
            string requestUri = "systemusers(" + myUserId + ")?$select=fullname";
            response = await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead);
            if (response.IsSuccessStatusCode)
            {
                JObject user = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                currentUser = user["fullname"].ToString();
            }
            else if (response.StatusCode == HttpStatusCode.NotFound)
            { currentUser = "[not registered]"; }
            else
            {
                Console.WriteLine("Error calling WhoAmI!");
                throw new CrmHttpResponseException(response.Content);
            }
            Console.WriteLine("\tCurrent user has system name '{0}'.", currentUser);
            #endregion Call an unbound function with no parameters.

            #region Call an unbound function that requires parameters.
            //Retrieve the time zone code for the specified time zone, using the GetTimeZoneCodeByLocalizedName 
            //function: https://msdn.microsoft.com/library/mt607644.aspx, which returns a GetTimeZoneCodeBy-
            //LocalizedNameResponse complex type: https://msdn.microsoft.com/library/mt607889.aspx.
            string timeZoneCode;
            int localeID = 1033;
            string timeZoneName = "Pacific Standard Time";
            JObject LocalizedNameResponse;
            //Demonstrates best practice of passing 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 + ")"]; 
            Console.WriteLine("Unbound function: GetTimeZoneCodeByLocalizedName");
            response = await httpClient.GetAsync(string.Join("", uria), 
                HttpCompletionOption.ResponseHeadersRead);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                LocalizedNameResponse = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
            }
            else
            {
                Console.WriteLine("Error calling GetTimeZoneCodeByLocalizedName!");
                throw new CrmHttpResponseException(response.Content);
            }
            timeZoneCode = LocalizedNameResponse["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.    
            //Retrieve the total time, in minutes, spent on all tasks associated with an incident.
            //Uses the CalculateTotalTimeIncident function: https://msdn.microsoft.com/library/mt593054.aspx, 
            //which returns a CalculateTotalTimeIncidentResponse complex type: 
            //https://msdn.microsoft.com/library/mt607924.aspx.
            string totalTime;
            string boundUri = incident1Uri + @"/Microsoft.Dynamics.CRM.CalculateTotalTimeIncident()";
            Console.WriteLine("Bound function: CalculateTotalTimeIncident");
            response = await httpClient.GetAsync(boundUri, HttpCompletionOption.ResponseHeadersRead);
            if (response.IsSuccessStatusCode)
            {
                JObject cttir = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                totalTime = cttir["TotalTime"].ToString();
            }
            else
            {
                Console.WriteLine("Error calling CalculateTotalTimeIncident!");
                throw new CrmHttpResponseException(response.Content);
            }
            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.
            //Close an opportunity and marks it as won. Uses the WinOpportunity action: 
            //https://msdn.microsoft.com/library/mt607971.aspx, 
            //which takes a int32 status code and an opportunityclose entity type: 
            //https://msdn.microsoft.com/library/mt593099.aspx.
            JObject opportClose = new JObject();
            opportClose["subject"] = "Won Opportunity";
            opportClose["opportunityid@odata.bind"] = opportunity1Uri;
            JObject winOpportParams = new JObject();
            winOpportParams["Status"] = 3;
            winOpportParams["OpportunityClose"] = opportClose;
            Console.WriteLine("Unbound action: WinOpportunity");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post, "WinOpportunity",
                winOpportParams);
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine("Error calling WinOpportunity!");
                throw new CrmHttpResponseException(response.Content);
            }
            Console.WriteLine("\tOpportunity won.");
            #endregion Call an unbound action that requires parameters.

            #region Call a bound action that requires parameters.
            //Add a new letter tracking activity to the current user's queue. Uses the AddToQueue 
            //action: https://msdn.microsoft.com/library/mt607880.aspx, which is bound to the queue 
            //entity type: https://msdn.microsoft.com/library/mt607886.aspx, and returns a 
            //AddToQueueResponse complex type: https://msdn.microsoft.com/en-us/library/mt608105.aspx.
            string queueItemId;
            //Create a letter tracking instance.
            string letterUri;
            JObject letter = new JObject();
            letter["description"] = "Example letter";
            Console.WriteLine("Bound action: AddToQueue");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post, "letters", letter);
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                letterUri = response.Headers.GetValues("OData-EntityId").FirstOrDefault();
                entityUris.Add(letterUri);
            }
            else
            {
                Console.WriteLine("Error creating tracking letter!");
                throw new CrmHttpResponseException(response.Content);
            }

            //Retrieve the ID associated with this new letter tracking activity.
            string letterActivityId;
            response = await httpClient.GetAsync(letterUri + "?$select=activityid",
                HttpCompletionOption.ResponseContentRead);
            if (response.IsSuccessStatusCode)
            {
                JObject letterRetreived = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                letterActivityId = letterRetreived["activityid"].ToString();
            }
            else
            {
                Console.WriteLine("Error retrieving tracking letter activity ID!");
                throw new CrmHttpResponseException(response.Content);
            }

            //Retrieve URL to current user's queue.
            string myQueueUri;
            response = await httpClient.GetAsync("systemusers(" + myUserId + ")/queueid/$ref",
                HttpCompletionOption.ResponseContentRead);
            if (response.IsSuccessStatusCode)
            {
                JObject queueRef = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                myQueueUri = queueRef["@odata.id"].ToString();
            }
            else
            {
                Console.WriteLine("Error retrieving current user queue URL!");
                throw new CrmHttpResponseException(response.Content);
            }

            //Add letter activity to current user's queue, then return its queue ID.
            JObject addToQueueParams = new JObject();
            addToQueueParams["Target"] = JObject.Parse(
              @"{activityid: '" + letterActivityId + @"', '@odata.type': 'Microsoft.Dynamics.CRM.letter' }");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post,
                myQueueUri + "/Microsoft.Dynamics.CRM.AddToQueue", addToQueueParams);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                JObject queueResponse = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                queueItemId = queueResponse["QueueItemId"].ToString();
            }
            else
            {
                Console.WriteLine("Error adding letter activity to queue!");
                throw new CrmHttpResponseException(response.Content);
            }
            Console.WriteLine("\tQueueItemId returned from AddToQueue action: {0}", queueItemId);
            #endregion Call a bound action that requires parameters.

            //Attempt to load the associated managed solution so that we can call its custom actions. 
            await InstallCustomSolutionAsync(true);
            if (customSolutionID == null)
            {
                Console.WriteLine("Failed to install custom solution, so custom operations cannot be called.");
                return;
            }

            #region 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. 
            string annote1Url;
            JObject note1 = JObject.Parse(
                @"{NoteTitle: 'Note Title', NoteText: 'The text content of the note.'}");
            string actionUri = contact1Uri + "/Microsoft.Dynamics.CRM.sample_AddNoteToContact";
            Console.WriteLine("Custom action: sample_AddNoteToContact");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post, actionUri, note1);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                JObject contact = JsonConvert.DeserializeObject<JObject>(await
                    response.Content.ReadAsStringAsync());
                annote1Url = httpClient.BaseAddress + "/annotations(" + contact["annotationid"] + ")";
            }
            else
            {
                Console.WriteLine("Error calling custom action sample_AddNoteToContact!");
                throw new CrmHttpResponseException(response.Content);
            }
            Console.WriteLine("\tA note with the title '{0}' was created and " +
                "associated with the contact {2}.",
                note1["NoteTitle"], note1["NoteText"],
                contact1["firstname"] + " '" + contact1["lastname"] + "'");
            #endregion Call a bound custom action that requires parameters.

            #region Call an unbound custom action that requires parameters.
            //Create a customer of the specified type, using the custom action sample_CreateCustomer,
            //which takes two prams: the type of customer ('account' or 'contact') and the name of 
            //the new customer.
            string customerName1 = "New account customer (sample)";
            JObject customerParam = JObject.Parse(
                @"{CustomerType: 'account', AccountName: '" + customerName1 + "'}");
            Console.WriteLine("Custom action: sample_CreateCustomer");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post,
                "sample_CreateCustomer", customerParam);
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine("Error calling custom action sample_CreateCustomer!");
                throw new CrmHttpResponseException(response.Content);
            }
            Console.WriteLine("\tThe account '" + customerName1 + "' was created.");

            //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.)
            customerParam = JObject.Parse(
                @"{CustomerType: 'contact', AccountName: '" + customerName1 + "'}");
            response = await SendAsJsonAsync(httpClient, HttpMethod.Post,
                "sample_CreateCustomer", customerParam);
            if (response.IsSuccessStatusCode)
            { Console.WriteLine("\tCall to CreateCustomer not expected to succeed."); }
            else
            {
                CrmHttpResponseException ex = new CrmHttpResponseException(response.Content);
                Console.WriteLine("\tExpected Error: " + ex.Message);
            }
            #endregion Call an unbound custom action that requires parameters.
        }

        /// <summary> Retrieves the solution ID associated with a solution name </summary>
        /// <param name="solutionName">Unique name of the solution (uniquename)</param>
        /// <returns>The solutionid property for this solution if found; otherwise null.</returns>
        private async Task<string> GetSolutionIDAsync(string solutionName)
        {
            HttpResponseMessage response;
            string solutionID = null;
            if (String.IsNullOrEmpty(solutionName)) { return null; }
            string queryOptions = "solutions?$select=solutionid&$filter=uniquename eq '" + solutionName + "'";
            response = await httpClient.GetAsync(queryOptions, HttpCompletionOption.ResponseHeadersRead);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                JObject solutionArray = JsonConvert.DeserializeObject<JObject>(await 
                    response.Content.ReadAsStringAsync());
                //There can only be zero or one returned record when filtering on a unique property.
                if (!solutionArray["value"].Any())
                { solutionID = null; }
                else
                { solutionID = solutionArray["value"].First()["solutionid"].ToString(); }
            }
            else
            { throw new CrmHttpResponseException(response.Content); }
            return solutionID;
        }

        /// <summary> Installs (or uninstalls) the custom, managed solution associated with 
        /// this sample </summary>
        /// <remarks>Uses the ImportSolution action: https://msdn.microsoft.com/library/mt608117.aspx
        /// </remarks>
        /// <param name="install">true to install (default); otherwise, false to uninstall</param>
        /// <returns>void</returns>
        private async Task InstallCustomSolutionAsync(bool install = true)
        {
            HttpResponseMessage response;
            //Check first if the solution is already installed by retrieving its ID.
            customSolutionID = await GetSolutionIDAsync(customSolutionName);

            //Request to install and solution is not already present
            if (install == true && customSolutionID == null)
            {
                //Locate the custom solution zip file, which should have been copied over to the build 
                //output directory.
                string solutionPath = Directory.GetCurrentDirectory() + "\\" + customSolutionFilename;
                if (!File.Exists(solutionPath))
                { return; }
                //Read the solution package into memory
                byte[] packageBytes = File.ReadAllBytes(solutionPath);
                //Import the solution package.
                JObject importParams = new JObject();
                importParams["CustomizationFile"] = packageBytes;
                importParams["OverwriteUnmanagedCustomizations"] = false;
                importParams["PublishWorkflows"] = false;
                importParams["ImportJobId"] = Guid.NewGuid();
                response = await SendAsJsonAsync(httpClient, HttpMethod.Post, "ImportSolution", importParams);
                if (response.IsSuccessStatusCode)
                {
                    customSolutionID = await GetSolutionIDAsync(customSolutionName);
                    string solutionUri = httpClient.BaseAddress.ToString() + "solutions(" + customSolutionID + ")";
                    entityUris.Add(solutionUri);  //Add to lifetime-managed records.
                    return;
                }
                else
                { throw new CrmHttpResponseException(response.Content); }
            }
            //Request to uninstall and solution is present. 
            else if (install == false && customSolutionID != null)
            {
                string solutionUri = httpClient.BaseAddress.ToString() + "solutions(" + customSolutionID + ")";
                response = httpClient.DeleteAsync(solutionUri).Result;
                customSolutionID = null;
            }
        }

        static void Main(string[] args)
        {
            FunctionsAndActions app = new FunctionsAndActions();
            try
            {
                //Read configuration file and connect to specified CRM server.
                app.ConnectToCRM(args);
                app.CreateRequiredRecords();
                Task.WaitAll(Task.Run(async () => await app.RunAsync()));
            }
            catch (System.Exception ex) { DisplayException(ex);
            }
            finally
            {
                if (app.httpClient != null)
                {
                    app.DeleteRequiredRecords(true);

                    app.httpClient.Dispose();
                }
                Console.WriteLine("Press <Enter> to exit the program.");
                Console.ReadLine();
            }
        }

        /// <summary>
        /// Obtains the connection information from the application's configuration file, then 
        /// uses this info to connect to the specified CRM service.
        /// </summary>
        /// <param name="args"> Command line arguments. The first specifies the name of the 
        ///  connection string setting. </param>
        private void ConnectToCRM(String[] cmdargs)
        {
            //Create a helper object to read app.config for service URL and application 
            // registration settings.
            FileConfiguration config = null;
            if (cmdargs.Length > 0)
            { config = new FileConfiguration(cmdargs[0]); }
            else
            { config = new FileConfiguration(null); }
            //Create a helper object to authenticate the user with this connection info.
            Authentication auth = new Authentication(config);
            //Next use a HttpClient object to connect to specified CRM Web service.
            httpClient = new HttpClient(auth.ClientHandler, true);
            //Define the Web API base address, the max period of execute time, the 
            // default OData version, and the default response payload format.
            httpClient.BaseAddress = new Uri(config.ServiceUrl + "api/data/v8.1/");
            httpClient.Timeout = new TimeSpan(0, 2, 0);
            httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
            httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
        }

        /// <summary> Creates the CRM entity instances used by this sample. </summary>
        private void CreateRequiredRecords()
        {
            //Create a parent account, an associated incident with three associated tasks 
            //(required for CalculateTotalTimeIncident).
            JObject account1 = new JObject();
            string account1Uri;
            account1["name"] = "Fourth Coffee";
            HttpResponseMessage response = SendAsJsonAsync(httpClient, HttpMethod.Post,
                "accounts", account1).Result;
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                account1Uri = response.Headers.GetValues("OData-EntityId").FirstOrDefault();
                entityUris.Add(account1Uri);
            }
            else
            { throw new CrmHttpResponseException(response.Content); }

            JArray tasks = new JArray(new JObject[]
            {
                JObject.Parse(@"{subject: 'Task 1', actualdurationminutes: 30}"),
                JObject.Parse(@"{subject: 'Task 2', actualdurationminutes: 30}"),
                JObject.Parse(@"{subject: 'Task 3', actualdurationminutes: 30}")
            }
            );
            JObject incident1 = new JObject();
            incident1["title"] = "Sample Case";
            incident1["customerid_account@odata.bind"] = account1Uri;
            incident1["Incident_Tasks"] = tasks;
            response = SendAsJsonAsync(httpClient, HttpMethod.Post, "incidents", incident1).Result;
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                incident1Uri = response.Headers.GetValues("OData-EntityId").FirstOrDefault();
                entityUris.Add(incident1Uri);
            }
            else
            { throw new CrmHttpResponseException(response.Content); }
            //Close the associated tasks (so that they represent completed work).
            JObject incidentTaskRefs;
            //Property value set used to mark tasks as completed. 
            JObject completeCode = JObject.Parse(@"{statecode: 1, statuscode: 5}");
            response = httpClient.GetAsync(incident1Uri + "/Incident_Tasks/$ref",
                HttpCompletionOption.ResponseContentRead).Result;
            if (response.IsSuccessStatusCode)
            {
                incidentTaskRefs = JsonConvert.DeserializeObject<JObject>
                    (response.Content.ReadAsStringAsync().Result);
            }
            else
            { throw new CrmHttpResponseException(response.Content); }
            foreach (var taskRef in incidentTaskRefs["value"])
            {
                response = SendAsJsonAsync(httpClient, new HttpMethod("PATCH"), 
                    taskRef["@odata.id"].ToString(), completeCode).Result;
                if (!response.IsSuccessStatusCode)
                { throw new CrmHttpResponseException(response.Content); }
            }

            //Create another account and associated opportunity (required for CloseOpportunityAsWon).
            JObject account2 = new JObject();
            string account2Uri;
            account2["name"] = "Coho Winery";
            account2["opportunity_customer_accounts"] = JArray.Parse(@"[{ name: 'Opportunity to win' }]");
            response = SendAsJsonAsync(httpClient, HttpMethod.Post, "accounts", account2).Result;
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                account2Uri = response.Headers.GetValues("OData-EntityId").FirstOrDefault();
                entityUris.Add(account2Uri);
            }
            else
            { throw new CrmHttpResponseException(response.Content); }
            //Retrieve the URI to the opportunity.
            JObject custOpporRefs;
            response = httpClient.GetAsync(account2Uri + "/opportunity_customer_accounts/$ref",
                HttpCompletionOption.ResponseContentRead).Result;
            if (response.IsSuccessStatusCode)
            {
                custOpporRefs = JsonConvert.DeserializeObject<JObject>
                    (response.Content.ReadAsStringAsync().Result);
                opportunity1Uri = custOpporRefs["value"][0]["@odata.id"].ToString();
            }
            else
            { throw new CrmHttpResponseException(response.Content); }

            //Create a contact to use with custom action sample_AddNoteToContact 
            contact1 = JObject.Parse(@"{firstname: 'Jon', lastname: 'Fogg'}");
            response = SendAsJsonAsync(httpClient, HttpMethod.Post, "contacts", contact1).Result;
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                contact1Uri = response.Headers.GetValues("OData-EntityId").FirstOrDefault();
                entityUris.Add(contact1Uri);
            }
            else
            { throw new CrmHttpResponseException(response.Content); }
        }

        /// <summary> Deletes the CRM entity instance sample data created by this sample. </summary>
        /// <param name="prompt">True to prompt the user for confirmation and display results; 
        ///   otherwise False to execute silently.</param>
        /// <returns>Number of entity instances deleted</returns>
        private int DeleteRequiredRecords(bool prompt)
        {
            if (entityUris.Count == 0) return 0;
            if (prompt)
            {
                Console.Write("\nDo you want these sample entity records deleted? (y/n) [y]: ");
                String answer = Console.ReadLine();
                answer = answer.Trim();
                if (!(answer.StartsWith("y") || answer.StartsWith("Y") ||
                    answer == String.Empty))
                { return 0; }
            }
            HttpResponseMessage response;
            int successCnt = 0, failCnt = 0;
            HttpContent lastBadResponseContent = null;
            foreach (string ent in entityUris)
            {
                response = httpClient.DeleteAsync(ent).Result;
                if (response.IsSuccessStatusCode) 
                { successCnt++; }
                else if (response.StatusCode == HttpStatusCode.NotFound) 
                {; } //Entity may have been deleted by another user or via cascade delete.
                else //Failed to delete
                {
                    failCnt++;
                    lastBadResponseContent = response.Content;
                }
            }
            entityUris.Clear();
            if (failCnt > 0)
            {
                //Throw last failure.
                throw new CrmHttpResponseException(lastBadResponseContent);
            }
            if (prompt)
            { Console.WriteLine("Deleted {0} records!", successCnt); }
            return successCnt;
        }

        /// <summary> Sends an HTTP message containing a JSON payload to the target URL. </summary>
        /// <typeparam name="T">Type of the data to send in the message content (payload)</typeparam>
        /// <param name="client">A preconfigured HTTP client</param>
        /// <param name="method">The HTTP method to invoke</param>
        /// <param name="requestUri">The relative URL of the message request</param>
        /// <param name="value">The data to send in the payload. The data will be converted to a 
        /// serialized JSON payload. </param>
        /// <returns>An HTTP response message</returns>
        private async Task<HttpResponseMessage> SendAsJsonAsync<T>(HttpClient client,
            HttpMethod method, string requestUri, T value)
        {
            string content;
            if (value.GetType().Name.Equals("JObject"))
            { content = value.ToString(); }
            else
            {
                content = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
                { DefaultValueHandling = DefaultValueHandling.Ignore });
            }
            HttpRequestMessage request = new HttpRequestMessage(method, requestUri);
            request.Content = new StringContent(content);
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
            return await client.SendAsync(request);
        }

        /// <summary> Helper method to display caught exceptions </summary>
        private static void DisplayException(Exception ex)
        {
            Console.WriteLine("The application terminated with an error.");
            Console.WriteLine(ex.Message);
            while (ex.InnerException != null)
            {
                Console.WriteLine("\t* {0}", ex.InnerException.Message);
                ex = ex.InnerException;
            }
        }

    }
}

関連項目

Microsoft Dynamics 365 Web API の使用
Web API 関数の使用
Web API アクションの使用
Web API のサンプル
Web API 機能およびアクションのサンプル
Web API 機能およびアクションのサンプル (クライアント側 JavaScript)
Web API 基本操作のサンプル (C#)
Web API クエリ データのサンプル (C#)
Web API 条件付き演算サンプル (C#)

Microsoft Dynamics 365

© 2017 Microsoft. All rights reserved. 著作権