rksoftware

Visual Studio とか C# とかが好きです

Dataverse の WebAPI で Dataverse のテーブルに列追加する C# コード その2

目次

Dataverse の WebAPI を C# で叩く系記事たちの目次です。

rksoftware.hatenablog.com

今回の本文

rksoftware.hatenablog.com

rksoftware.hatenablog.com

前回の続きです。
これまでデータ取得、テーブルに列追加、行追加をしてきましたが、今回は列追加その2です。
API で取得した列定義 JSON をもとに列を追加してみます。。

■ 動かし方

コマンドライン引数で、WebAPIのエンドポイントを入れます。Web の GUI で 「テーブル 定義への API リンク」をした時の URL です。

■ 概要

  1. 事前にテーブルの列定義の JSON を取得し、一列分の定義部分だけ用意しておく
  2. その定義から MetadataIdCreatedOnModifiedOn を削除
  3. LogicalNameSchemaNameLabel を新たに追加する列名に変更
  4. Post。

簡単ですね。
実際はもっと様々な方の型の列があり複雑でしょうが、たいていの場合、テーブルへの列追加は「ほかのテーブルに追加した列とほぼ同じ設定の列」「同テーブルの既存の列とほぼ同じ設定の列」でしょうから、この定義を取得して少し書き換えるとその JSON で列追加ができる、は何かに使えそうです。しかし要改善。
次回以降、改善してみますね。

using System.Text;

string s = args[0] + "/Attributes";

string json = """
        {
            "@odata.type": "#Microsoft.Dynamics.CRM.MemoAttributeMetadata",
            "HasChanged": null,
            "AttributeOf": null,
            "AttributeType": "Memo",
            "ColumnNumber": 37,
            "DeprecatedVersion": null,
            "IntroducedVersion": "1.0",
            "EntityLogicalName": "crf6f_newtable001",
            "IsCustomAttribute": true,
            "IsPrimaryId": false,
            "IsValidODataAttribute": true,
            "IsPrimaryName": false,
            "IsValidForCreate": true,
            "IsValidForRead": true,
            "IsValidForUpdate": true,
            "CanBeSecuredForRead": true,
            "CanBeSecuredForCreate": true,
            "CanBeSecuredForUpdate": true,
            "IsSecured": false,
            "IsRetrievable": false,
            "IsFilterable": false,
            "IsSearchable": false,
            "IsManaged": false,
            "LinkedAttributeId": null,
            "LogicalName": "crf6f_user_multiline_richtext_01_02",
            "IsValidForForm": true,
            "IsRequiredForForm": false,
            "IsValidForGrid": true,
            "SchemaName": "crf6f_user_multiline_richtext_01_02",
            "ExternalName": null,
            "IsLogical": false,
            "IsDataSourceSecret": false,
            "InheritsFrom": null,
            "SourceType": null,
            "AutoNumberFormat": null,
            "Format": "Text",
            "ImeMode": "Auto",
            "MaxLength": 2000,
            "IsLocalizable": false,
            "AttributeTypeName": {
                "Value": "MemoType"
            },
            "Description": {
                "LocalizedLabels": [
                    {
                        "Label": "",
                        "LanguageCode": 1041,
                        "IsManaged": false,
                        "HasChanged": null
                    }
                ],
                "UserLocalizedLabel": {
                    "Label": "",
                    "LanguageCode": 1041,
                    "IsManaged": false,
                    "HasChanged": null
                }
            },
            "DisplayName": {
                "LocalizedLabels": [
                    {
                        "Label": "new rich 02",
                        "LanguageCode": 1041,
                        "IsManaged": false,
                        "HasChanged": null
                    }
                ],
                "UserLocalizedLabel": {
                    "Label": "new rich 02",
                    "LanguageCode": 1041,
                    "IsManaged": false,
                    "HasChanged": null
                }
            },
            "IsAuditEnabled": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyauditsettings"
            },
            "IsGlobalFilterEnabled": {
                "Value": false,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyglobalfiltersettings"
            },
            "IsSortableEnabled": {
                "Value": false,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyissortablesettings"
            },
            "IsCustomizable": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "iscustomizable"
            },
            "IsRenameable": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "isrenameable"
            },
            "IsValidForAdvancedFind": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifysearchsettings"
            },
            "RequiredLevel": {
                "Value": "None",
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings"
            },
            "CanModifyAdditionalSettings": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyadditionalsettings"
            },
            "Settings": [],
            "FormatName": {
                "Value": "RichText"
            }
        }
""";

/*
string json = """
        {
            "@odata.type": "#Microsoft.Dynamics.CRM.MemoAttributeMetadata",
            "MetadataId": "883d1c59-a975-f011-b4cb-00224862d28c",
            "HasChanged": null,
            "AttributeOf": null,
            "AttributeType": "Memo",
            "ColumnNumber": 37,
            "DeprecatedVersion": null,
            "IntroducedVersion": "1.0",
            "EntityLogicalName": "crf6f_newtable001",
            "IsCustomAttribute": true,
            "IsPrimaryId": false,
            "IsValidODataAttribute": true,
            "IsPrimaryName": false,
            "IsValidForCreate": true,
            "IsValidForRead": true,
            "IsValidForUpdate": true,
            "CanBeSecuredForRead": true,
            "CanBeSecuredForCreate": true,
            "CanBeSecuredForUpdate": true,
            "IsSecured": false,
            "IsRetrievable": false,
            "IsFilterable": false,
            "IsSearchable": false,
            "IsManaged": false,
            "LinkedAttributeId": null,
            "LogicalName": "crf6f_user_multiline_richtext_01_02",
            "IsValidForForm": true,
            "IsRequiredForForm": false,
            "IsValidForGrid": true,
            "SchemaName": "crf6f_user_multiline_richtext_01_02",
            "ExternalName": null,
            "IsLogical": false,
            "IsDataSourceSecret": false,
            "InheritsFrom": null,
            "CreatedOn": "2025-08-10T05:17:59Z",
            "ModifiedOn": "2025-08-10T05:17:59Z",
            "SourceType": null,
            "AutoNumberFormat": null,
            "Format": "Text",
            "ImeMode": "Auto",
            "MaxLength": 2000,
            "IsLocalizable": false,
            "AttributeTypeName": {
                "Value": "MemoType"
            },
            "Description": {
                "LocalizedLabels": [
                    {
                        "Label": "",
                        "LanguageCode": 1041,
                        "IsManaged": false,
                        "MetadataId": "c1578bc6-7d47-4a46-bb14-bed6b34f9780",
                        "HasChanged": null
                    }
                ],
                "UserLocalizedLabel": {
                    "Label": "",
                    "LanguageCode": 1041,
                    "IsManaged": false,
                    "MetadataId": "c1578bc6-7d47-4a46-bb14-bed6b34f9780",
                    "HasChanged": null
                }
            },
            "DisplayName": {
                "LocalizedLabels": [
                    {
                        "Label": "\u30e6\u30fc\u30b6\u30fc\u5b9a\u7fa9\u8907\u6570\u884c\u30ea\u30c3\u30c1\u30c6\u30ad\u30b9\u30c8_02",
                        "LanguageCode": 1041,
                        "IsManaged": false,
                        "MetadataId": "f6642691-599d-4598-8cb1-ea15b41d75db",
                        "HasChanged": null
                    }
                ],
                "UserLocalizedLabel": {
                    "Label": "\u30e6\u30fc\u30b6\u30fc\u5b9a\u7fa9\u8907\u6570\u884c\u30ea\u30c3\u30c1\u30c6\u30ad\u30b9\u30c8_02",
                    "LanguageCode": 1041,
                    "IsManaged": false,
                    "MetadataId": "f6642691-599d-4598-8cb1-ea15b41d75db",
                    "HasChanged": null
                }
            },
            "IsAuditEnabled": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyauditsettings"
            },
            "IsGlobalFilterEnabled": {
                "Value": false,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyglobalfiltersettings"
            },
            "IsSortableEnabled": {
                "Value": false,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyissortablesettings"
            },
            "IsCustomizable": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "iscustomizable"
            },
            "IsRenameable": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "isrenameable"
            },
            "IsValidForAdvancedFind": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifysearchsettings"
            },
            "RequiredLevel": {
                "Value": "None",
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings"
            },
            "CanModifyAdditionalSettings": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "canmodifyadditionalsettings"
            },
            "Settings": [],
            "FormatName": {
                "Value": "RichText"
            }
        }
""";
*/
/*
string json = """
{  
 "AttributeType": "String",  
 "AttributeTypeName": {  
  "Value": "StringType"  
 },  
 "Description": {  
  "@odata.type": "Microsoft.Dynamics.CRM.Label",  
  "LocalizedLabels": [  
   {  
    "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",  
    "Label": "Type the name of the bank",  
    "LanguageCode": 1033  
   }  
  ]  
 },  
 "DisplayName": {  
  "@odata.type": "Microsoft.Dynamics.CRM.Label",  
  "LocalizedLabels": [  
   {  
    "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",  
    "Label": "Bank Name 02",  
    "LanguageCode": 1033  
   }  
  ]  
 },  
 "RequiredLevel": {  
  "Value": "None",  
  "CanBeChanged": true,  
  "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings"  
 },  
 "SchemaName": "new_BankName_02",  
 "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",  
 "FormatName": {  
  "Value": "Text"  
 },  
 "MaxLength": 100  
}  
""";
*/

string r = await new RkDataverseHttpClient(s).PostAsync(json);
Console.WriteLine(r);


class RkDataverseHttpClient
{
    public string Resource { get; init; }
    public Uri BaseAddress { get; init; }
    public string Path { get; init; }
    public static string ClientId { get; } = "51f81489-12ee-4a9e-aaae-a2591f45987d";
    public static string RedirectUri { get; } = "http://localhost";

    Microsoft.Identity.Client.AuthenticationResult Token { get; set; }
    HttpClient HttpClient { get; init; }

    public RkDataverseHttpClient(string resource)
    {
        var uri = new Uri(resource);
        Resource = uri.Scheme + "://" + uri.Host;
        BaseAddress = new Uri(Resource + "/api/data/v9.2/");
        Path = new string(resource.Skip(BaseAddress.AbsoluteUri.Length).ToArray());
        Authentication().GetAwaiter().GetResult();
        HttpClient = BuildHttpClient();
    }

    async Task<Microsoft.Identity.Client.AuthenticationResult> Authentication()
    {
        var authBuilder = Microsoft.Identity.Client.PublicClientApplicationBuilder.Create(ClientId)
                       .WithAuthority(Microsoft.Identity.Client.AadAuthorityAudience.AzureAdMultipleOrgs)
                       .WithRedirectUri(RedirectUri)
                       .Build();
        string[] scopes = { Resource + "/user_impersonation" };
        Microsoft.Identity.Client.AuthenticationResult token = await authBuilder.AcquireTokenInteractive(scopes).ExecuteAsync();
        return Token = token;
    }

    HttpClient BuildHttpClient()
    {
        HttpClient client = new HttpClient() { BaseAddress = BaseAddress, Timeout = new TimeSpan(0, 2, 0) };
        System.Net.Http.Headers.HttpRequestHeaders headers = client.DefaultRequestHeaders;
        headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Token.AccessToken);
        headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
        return client;
    }

    public async Task<string> PostAsync(string json)
    {
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await HttpClient.PostAsync(Path, content);
        string jsonContent = null;
        if (response.IsSuccessStatusCode)
        {
            jsonContent = await response.Content.ReadAsStringAsync();
        }
        return jsonContent ?? "";
    }
}