使用实体元数据早期绑定调用动态 Web API



我想使用我的组织动态oData端点,但使用早期绑定类。但是,有很多早期绑定的工具,我想知道哪一个提供最佳的开发人员体验/阻力最小?

例如,有这个:

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

等等。那里有开发人员偏好/方法吗?

早期绑定类用于组织服务,这是一个 SOAP 服务。生成这些类的正常方法是使用 CrmSvcUtil。

OData 可用于组织数据服务或 Web API,但这些没有早期绑定类。

延伸阅读:介绍 Dynamics 365 Web 服务Microsoft

与标准 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;
}
}

这是一个简单的方法,我没有走得更远。 也许我们必须将其他对象称为选项集,日期时间(仅传递字符串(和实体引用,但这个简单的测试对我来说效果很好。我正在使用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)";

因此,它是架构名称,而不是字段名称。如果您在设置字段名称时使用驼峰大小写,您将在哪里遇到问题。我们可以通过(到那个可爱的(代码来解决这个问题

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;
}

并且您必须更改实体上的 ToExpandoObject .cs类(由插件生成(

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 Service Utility (CrmSvcUtil( 生成早期绑定。 它不仅仅是早期绑定,这就是为什么我们在所有项目中使用它的原因,但仅早期绑定功能就会让我卖掉它。 为了重新生成实体定义,您只需右键单击Visual Studio中的CS文件并选择"重新生成",几秒钟即可完成。

在我CRM开发的前3年,我使用了XrmToolbox"早期绑定生成器"插件,这也非常有用。

最新更新