簡體   English   中英

使用實體元數據早期綁定調用 Dynamics Web API

[英]Calling Dynamics Web API with Entity metadata early binding

我想使用我的組織動態 oData 端點,但使用早期綁定類。 但是,有很多早期綁定工具,我想知道哪一個提供了最好的開發人員體驗/最少的阻力?

例如,有這樣一個:

https://github.com/daryllabar/DLaB.Xrm.XrmToolBoxTools https://github.com/yagasoft/DynamicsCrm-CodeGenerator

等等。 是否有開發人員偏好/方法?

早期綁定類用於組織服務,它是一種 SOAP 服務。 生成這些類的正常方法是使用CrmSvcUtil

OData 可用於組織數據服務或 Web API,但它們沒有 Early Bound 類。

進一步閱讀: 介紹 Microsoft Dynamics 365 Web 服務

與標准 SOAP 早期綁定類一起使用並非不可能。 我們只需要有創意。 如果我們只使用基本屬性(字段,而不是關系,ecc),這似乎是可能的。 例如。 對於創建和更新,OData 不會接受整個早期有界類,只需傳遞屬性:

    class Program
{
    static void Main(string[] args)
    {
        string token = System.Threading.Tasks.Task.Run(() => GetToken()).Result;
        CRMWebAPI dynamicsWebAPI = new CRMWebAPI("https:/ORG.api.crm4.dynamics.com/api/data/v9.1/",
                token);


        CRMGetListOptions listOptions = new CRMGetListOptions
        {
            Select = new string[] { "EntitySetName" },
            Filter = "LogicalName eq 'contact'"
        };

        dynamic entityDefinitions = dynamicsWebAPI.GetList<ExpandoObject>("EntityDefinitions", listOptions).Result;

        Contact contact = new Contact
        {
            FirstName = "Felipe",
            LastName = "Test",
            MobilePhone = "38421254"
        };

        dynamic ret = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.Create(entityDefinitions.List[0].EntitySetName, KeyPairValueToObject(contact.Attributes))).Result;



}

    public static async Task<string> GetToken()
    {
        string api = "https://ORG.api.crm4.dynamics.com/";

        ClientCredential credential = new ClientCredential("CLIENT_ID", "CLIENT_SECRET");

        AuthenticationContext authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/commom/oauth2/authorize");
        return authenticationContext.AcquireTokenAsync(api, credential).Result.AccessToken;

    }

    public static object KeyPairValueToObject(AttributeCollection keyValuePairs)
    {
        dynamic expando = new ExpandoObject();
        var obj = expando as IDictionary<string, object>;
        foreach (var keyValuePair in keyValuePairs)
            obj.Add(keyValuePair.Key,  keyValuePair.Value);
        return obj;

    }
}

這是一個簡單的方法,我沒有更進一步。 也許我們必須將其他對象序列化為 OptionSets、DateTime(只傳遞字符串)和 EntityReferences,但這個簡單的測試對我來說效果很好。 我正在使用 Xrm.Tools.WebAPI 和 Microsoft.IdentityModel.Clients.ActiveDirectory。 也許這是一種方式。

[編輯]

所以我決定去創建一個沒有經過很好測試的方法來轉換屬性。 問題:我們必須遵循 OData 語句才能使用 API。 要更新/創建實體引用,我們可以使用它來引用https://www.inogic.com/blog/2016/02/set-values-of-all-data-types-using-web-api-in-dynamics -crm/所以

//到實體引用

entityToUpdateOrCreate["FIELD_SCHEMA_NAME@odata.bind"] = "/ENTITY_SET_NAME(GUID)";

所以,它是架構名稱,而不是字段名稱。 如果您在設置字段名稱時使用 CamelCase,您將在何處遇到問題。 我們可以用(那個可愛的)代碼解決這個問題

        public static object EntityToObject<T>(T entity) where T : Entity
    {
        dynamic expando = new ExpandoObject();
        var obj = expando as IDictionary<string, object>;
        foreach (var keyValuePair in entity.Attributes)
        {
            obj.Add(GetFieldName(entity, keyValuePair), CastEntityAttibutesValueOnDynamicObject(keyValuePair.Value));
        }
        return obj;

    }

    public static object CastEntityAttibutesValueOnDynamicObject(object attributeValue)
    {
        if (attributeValue.GetType().Name == "EntityReference")
         {
            CRMGetListOptions listOptions = new CRMGetListOptions
            {
                Select = new string[] { "EntitySetName" },
                Filter = $"LogicalName eq '{((EntityReference)attributeValue).LogicalName}'"
            };

            dynamic entitySetName = dynamicsWebAPI.GetList<ExpandoObject>("EntityDefinitions", listOptions).Result.List[0];

            return $"/{entitySetName.EntitySetName}({((EntityReference)attributeValue).Id})";
        }
        else if (attributeValue.GetType().Name == "OptionSetValue")
        {
            return ((OptionSetValue)attributeValue).Value;
        }
        else if (attributeValue.GetType().Name == "DateTime")
        {
            return ((DateTime)attributeValue).ToString("yyyy-MM-dd");
        }
        else if (attributeValue.GetType().Name == "Money")
        {
            return ((Money)attributeValue).Value;
        }
        else if (attributeValue.GetType().Name == "AliasedValue")
        {
            return CastEntityAttibutesValueOnDynamicObject(((AliasedValue)attributeValue).Value);
        }
        else
        {
            return attributeValue;
        }
    }

    public static string GetFieldName<T>(T entity, KeyValuePair<string, object> keyValuePair) where T : Entity
    {
        switch (keyValuePair.Value.GetType().Name)
        {
            case "EntityReference":
                var entityNameList = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.GetEntityDisplayNameList()).Result;

                var firstEntity = entityNameList.Where(x => x.LogicalName == entity.LogicalName).FirstOrDefault();

                var attrNameList = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.GetAttributeDisplayNameList(firstEntity.MetadataId)).Result;

                return attrNameList.Where(x => x.LogicalName == keyValuePair.Key).Single().SchemaName + "@odata.bind";
            case "ActivityParty":
                throw new NotImplementedException(); //TODO
            default:
                return keyValuePair.Key;
        }
    }

請注意,無論如何,這種方法似乎並不快或不好。 最好將所有這些值都設為靜態值,這樣我們就可以節省一些提取

[編輯 2]

我剛剛在 XRMToolBox 上發現了一個名為“Web API 的早期綁定生成器”的插件,它似乎是最好的選擇 如果您仍然對此感到好奇,也許您應該嘗試一下。 我想這是最好的方法。 最后的代碼是這樣的:

        static void Main(string[] args)
    {
        string token = Task.Run(() => GetToken()).Result;
        dynamicsWebAPI = new CRMWebAPI("https://ORG.api.crm4.dynamics.com/api/data/v9.1/",
                token);

        Contact contact = new Contact
        {
            FirstName = "Felipe",
            LastName = "Test",
            MobilePhone = "38421254",
            new_Salutation = new EntityReference(new_salutation.EntitySetName, new Guid("{BFA27540-7BB9-E611-80EE-FC15B4281C8C}")),
            BirthDate = new DateTime(1993, 04, 14),
        };

        dynamic ret = Task.Run(async () => await dynamicsWebAPI.Create(Contact.EntitySetName, contact.ToExpandoObject())).Result;
        Contact createdContact = dynamicsWebAPI.Get<Contact>(Contact.EntitySetName, ret, new CRMGetListOptions
        {
            Select = new string[] { "*" }
        }).Result;
    }

並且您必須更改 Entity.cs 類(由插件生成)上的 ToExpandoObject

        public ExpandoObject ToExpandoObject()
    {
        dynamic expando = new ExpandoObject();
        var expandoObject = expando as IDictionary<string, object>;
        foreach (var attributes in Attributes)
        {
            if (attributes.Key == GetIdAttribute())
            {
                continue;
            }

            var value = attributes.Value;
            var key = attributes.Key;

            if (value is EntityReference entityReference)
            {
                value = $"/{entityReference.EntitySetName}({entityReference.EntityId})";
            }
            else
            {
                key = key.ToLower();

                if (value is DateTime dateTimeValue)
                {
                    var propertyForAttribute = GetPublicInstanceProperties().FirstOrDefault(x =>
                        x.Name.Equals(key, StringComparison.InvariantCultureIgnoreCase));

                    if (propertyForAttribute != null)
                    {
                        var onlyDateAttr = propertyForAttribute.GetCustomAttribute<OnlyDateAttribute>();

                        if (onlyDateAttr != null)
                        {
                            value = dateTimeValue.ToString(OnlyDateAttribute.Format);
                        }
                    }
                }
            }

            expandoObject.Add(key, value);
        }

        return (ExpandoObject)expandoObject;
    }

鏈接: https : //github.com/davidyack/Xrm.Tools.CRMWebAPI

https://www.xrmtoolbox.com/plugins/crm.webApi.earlyBoundGenerator/

我們目前使用XrmToolkit ,它有自己的早期綁定版本,稱為 ProxyClasses,但允許您使用 CRM 服務實用程序 (CrmSvcUtil) 生成早期綁定。 它不僅僅是早期綁定,這就是我們在所有項目中使用它的原因,但僅早期綁定功能就會讓我大吃一驚。 為了重新生成實體定義,您只需右鍵單擊 Visual Studio 中的 cs 文件並選擇重新生成,即可在幾秒鍾內完成。

在我 CRM 開發的前 3 年中,我使用了 XrmToolbox “Early Bound Generator”插件,它也非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM