当前位置:网站首页>Dynamics 365: explain virtual entity from 0 to 1
Dynamics 365: explain virtual entity from 0 to 1
2022-07-24 15:40:00 【Stone-hdj】
from Dynamics 365 for Customer Engagement 9.0 Start , Virtual entities pass through Dynamics 365 Customer Engagement Seamlessly represent data as entities in , It realizes the data integration in the external system . It does not require data replication , There is usually no need for custom coding .
Virtual entities have the following limitations , But in addition to the following limitations , It is no different from other custom entities :
- The data is read-only . Virtual entity attribute is not supported in Dynamics 365 in CE The changes are being pushed back to the external system
- Only organization level permissions of entities are supported . Field level security is not supported
- For external data , Need to be abstractly modeled as D365 Those fields supported by , For example, you want to get the name of a record in the external system , Gender , Age field , So in a virtual entity , You need to create and name , Field types that match the gender and age fields , such as text, number, optionset, date, image, and lookup type
- The record of external data must have a GUID The primary key of the format is associated with the primary key in the virtual entity
- Cannot use calculated field , If you need to calculate , Need to be done in an external system or in data provider Intermediate processing .
- You cannot filter or sort the values of a column
- I won't support it Audit History
- Not for queue Enable virtual entities
- Virtual entities do not support BPF
- Once a virtual entity is created, it cannot be changed to an ordinary entity
1. Create a plug-in and register
This plug-in will implement Retrieve and Retrieve Multiple, The sample code is connected to another organization D365 in , obtain Account Record in the entity and display it .
Will these hardcode Writing to your plug-in is not a good way , I do this mainly to make it easier for you to see how it works , You need to properly handle these configuration information when writing your own code
For how to use the configuration information in the following code, see Azure Where can I find , You can refer to this blog below
Retrieve:
using Microsoft.Xrm.Sdk;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
namespace VirtualEntityODataProvider
{
public class Retrieve : IPlugin
{
//set these values for your D365 instance, user credentials and Azure AD clientid/token endpoint
string crmorg = "https://orgeXXXX.crm5.dynamics.com";
string clientid = "b004872a-XXXX-XXXX-XXXX-4a21868c04db";
string username = "[email protected]";
string userpassword = "XXXX";
string tokenendpoint = "https://login.microsoftonline.com/594a2057-XXXX-XXXX-XXXX-0bc293dfb025/oauth2/token";
string clientsecret = "mTQ8Q~2bc84~fMK5Z0qc123456XXXdaG";
//relative path to web api endpoint
string crmwebapi = "/api/data/v9.2";
string crmwebapipath = "/accounts({Id})?$select=name,accountid";
public void Execute(IServiceProvider serviceProvider)
{
//basic plugin set-up stuff
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = XXXX(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
tracingService.Trace($"Starting Tracing!");
try
{
EntityReference target = (EntityReference)context.InputParameters["Target"];
//build the authorization request for Azure AD
var reqstring = "client_id=" + clientid;
reqstring += "&client_secret=" + clientsecret;
reqstring += "&resource=" + Uri.EscapeUriString(crmorg);
reqstring += "&username=" + Uri.EscapeUriString(username);
reqstring += "&password=" + Uri.EscapeUriString(userpassword);
reqstring += "&grant_type=password";
//make the Azure AD authentication request
WebRequest req = WebRequest.Create(tokenendpoint);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reqstring);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
os.Close();
tracingService.Trace($"Request token completed");
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader tokenreader = new StreamReader(resp.GetResponseStream());
string responseBody = tokenreader.ReadToEnd();
tokenreader.Close();
tracingService.Trace($"Parsing token response");
//deserialize the Azure AD token response and get the access token to supply with the web api query
var tokenresponse = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(responseBody);
var token = tokenresponse["access_token"];
tracingService.Trace($"token:{token}");
//make the web api query
WebRequest crmreq = WebRequest.Create(crmorg + crmwebapi + crmwebapipath.Replace("{Id}", target.Id.ToString()));
crmreq.Headers = new WebHeaderCollection();
//use the access token from earlier as the authorization header bearer value
crmreq.Headers.Add("Authorization", "Bearer " + token);
crmreq.Headers.Add("OData-MaxVersion", "4.0");
crmreq.Headers.Add("OData-Version", "4.0");
crmreq.Headers.Add("Prefer", "odata.maxpagesize=500");
crmreq.Headers.Add("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
crmreq.ContentType = "application/json; charset=utf-8";
crmreq.Method = "GET";
HttpWebResponse crmresp = (HttpWebResponse)crmreq.GetResponse();
StreamReader crmreader = new StreamReader(crmresp.GetResponseStream());
string crmresponseBody = crmreader.ReadToEnd();
crmreader.Close();
tracingService.Trace($"Retrieve completed");
//deserialize the response
var crmresponseobj = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(crmresponseBody);
tracingService.Trace($"Retrieve result completed, crmresponseobj = {crmresponseobj}");
Entity verow = new Entity("cr8e0_otheraccount");
verow["cr8e0_otheraccountid"] = (Guid)crmresponseobj["accountid"];
verow["cr8e0_name"] = (string)crmresponseobj["name"];
//return a result
context.OutputParameters["BusinessEntity"] = verow;
}
catch (Exception e)
{
tracingService.Trace($"{e.Message} {e.StackTrace}");
if (e.InnerException != null)
tracingService.Trace($"{e.InnerException.Message} {e.InnerException.StackTrace}");
throw new InvalidPluginExecutionException(e.Message);
}
}
}
}
Retrieve Multiple:
using Microsoft.Xrm.Sdk;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
namespace VirtualEntityODataProvider
{
public class RetrieveMultiple : IPlugin
{
//set these values for your D365 instance, user credentials and Azure AD clientid/token endpoint
string crmorg = "https://orgeXXXX.crm5.dynamics.com";
string clientid = "b004872a-XXXX-XXXX-XXXX-4a21868c04db";
string username = "[email protected]";
string userpassword = "XXXX";
string tokenendpoint = "https://login.microsoftonline.com/594a2057-XXXX-XXXX-XXXX-0bc293dfb025/oauth2/token";
string clientsecret = "mTQ8Q~2bc84~fMK5Z0qc123456XXXdaG";
//relative path to web api endpoint
string crmwebapi = "/api/data/v9.2";
//web api query to execute - in this case all accounts that start with "A"
string crmwebapipath = "/accounts?$select=name,accountid&$filter=startswith(name,'A')";
public void Execute(IServiceProvider serviceProvider)
{
//basic plugin set-up stuff
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
tracingService.Trace($"Starting Tracing!");
try
{
EntityCollection results = new EntityCollection();
//build the authorization request for Azure AD
var reqstring = "client_id=" + clientid;
reqstring += "&client_secret=" + clientsecret;
reqstring += "&resource=" + Uri.EscapeUriString(crmorg);
reqstring += "&username=" + Uri.EscapeUriString(username);
reqstring += "&password=" + Uri.EscapeUriString(userpassword);
reqstring += "&grant_type=password";
//make the Azure AD authentication request
WebRequest req = WebRequest.Create(tokenendpoint);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reqstring);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
os.Close();
tracingService.Trace($"Request token completed");
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader tokenreader = new StreamReader(resp.GetResponseStream());
string responseBody = tokenreader.ReadToEnd();
tokenreader.Close();
tracingService.Trace($"Parsing token response");
//deserialize the Azure AD token response and get the access token to supply with the web api query
var tokenresponse = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(responseBody);
var token = tokenresponse["access_token"];
tracingService.Trace($"token:{token}");
//make the web api query
WebRequest crmreq = WebRequest.Create(crmorg + crmwebapi + crmwebapipath);
crmreq.Headers = new WebHeaderCollection();
//use the access token from earlier as the authorization header bearer value
crmreq.Headers.Add("Authorization", "Bearer " + token);
crmreq.Headers.Add("OData-MaxVersion", "4.0");
crmreq.Headers.Add("OData-Version", "4.0");
crmreq.Headers.Add("Prefer", "odata.maxpagesize=500");
crmreq.Headers.Add("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
crmreq.ContentType = "application/json; charset=utf-8";
crmreq.Method = "GET";
HttpWebResponse crmresp = (HttpWebResponse)crmreq.GetResponse();
StreamReader crmreader = new StreamReader(crmresp.GetResponseStream());
string crmresponseBody = crmreader.ReadToEnd();
crmreader.Close();
tracingService.Trace($"Retrieve multiple completed");
//deserialize the response
var crmresponseobj = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(crmresponseBody);
//loop through the response values
foreach (var row in crmresponseobj["value"].Children())
{
//create a new virtual entity of type lpa_demove
Entity verow = new Entity("cr8e0_otheraccount");
verow["cr8e0_otheraccountid"] = (Guid)row["accountid"];
verow["cr8e0_name"] = (string)row["name"];
//add it to the collection
results.Entities.Add(verow);
}
tracingService.Trace($"Retrieve results completed, there are {results.Entities.Count} items!");
//return the results
context.OutputParameters["BusinessEntityCollection"] = results;
}
catch (Exception e)
{
tracingService.Trace($"{e.Message} {e.StackTrace}");
if (e.InnerException != null)
tracingService.Trace($"{e.InnerException.Message} {e.InnerException.StackTrace}");
throw new InvalidPluginExecutionException(e.Message);
}
}
}
}
Note that the code above uses Newtonsoft This third party Nuget package , So we need to use ILMerge perhaps Costura.Fody To pack it into a dll.
Register plug-ins ( No need to register step, Follow up creation Data Provider It will be automatically added when MainOperation This step)

2. register Data Provider
Plugin Registeration Tool: Register -> Register New Data Provider


Solution: Here we choose to create a new solution, It will be filled in by us Data Source Entity( Virtual entity )
Data Source Entity: Choose to create a new data source
Assembly: Select the plug-in we just registered
Retrieve and Retrieve Multiple: Also choose what we just created
After registration, we will see , In the first step, the plug-in we created will be automatically filled in

And we found that the steps inside are not editable

3. Newly created in the system Data Source
Setting -> Administration -> Virtual Entity Data Sources

Select the... We created in step 2 above Data Provider

Fill in Name And save 
4. Create virtual entities
The entity needs to put Virtual Entity Choose ,Data Source Select the data source we just created

Note: The fields in this step should correspond to those in the above code , Here's the picture


5. effect
Let's use advanced search to test , Advanced lookup will call Retrieve Multiple

Because we do filtering in the code , Extract only A At the beginning Account
When we click on one of the records to open , It will be called Retrieve

Reference link :
Get started with virtual entities (Developer Guide for Dynamics 365 Customer Engagement) | Microsoft Docs
https://docs.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/virtual-entities/get-started-ve?view=op-9-1#limitations-of-virtual-entities Configure virtual entities using custom data sources - Microsoft MVP(15-18) Luo Yong - Blog Garden (cnblogs.com)
https://www.cnblogs.com/luoyong0201/p/Dynamics_365_Develop_Virtual_Entity_with_Custom_Data_Provider.htmlUsing Dynamics 365 virtual entities to show data from an external organization (alexanderdevelopment.net)
https://alexanderdevelopment.net/post/2018/05/28/using-dynamics-365-virtual-entities-to-show-data-from-an-external-organization/
边栏推荐
- PyTorch的自动求导
- Analysys analysis "2022 China data security market data monitoring report" was officially launched
- Is Huishang futures platform safe? Is it OK to open a futures account?
- Varnish4.0 cache agent configuration
- IP protocol - network segment division
- 【TA-霜狼_may-《百人计划》】图形3.4 延迟渲染管线介绍
- Dynamics crm: [problem solved]cannot open SQL encryption symmetric key because symmetric key password
- 各种Normalization的直观理解
- [tkinter美化] 脱离系统样式的窗口(三系统通用)
- Fine tune layoutlm V3 for bill data processing and content recognition
猜你喜欢

Analysis of some difficulties in VAE (variational self encoder)

有了这个机器学习画图神器,论文、博客都可以事半功倍了!

Nine key measures to maintain server security in Hong Kong

Kubectl_好用的命令行工具:oh-my-zsh_技巧和窍门

yolov3 训练自己的数据集

Error 1053: the service did not respond to the start or control request in a timely fashion

VAE(变分自编码器)的一些难点分析
![[adaptiveavgpool3d] pytorch tutorial](/img/d0/60ee74ff554effa06084d5d01a03e1.png)
[adaptiveavgpool3d] pytorch tutorial

【量化测试】

JMeter - call the interface for uploading files or pictures
随机推荐
2022 robocom world robot developer competition - undergraduate group (provincial competition) -- question 1: don't waste gold (finished)
Istio1.12:安装和快速入门
4279. Cartesian tree
请问好的券商的排名?网上开户安全吗
yolov3 训练自己的数据集
mysql源码分析——索引的数据结构
在LAMP架构中部署Zabbix监控系统及邮件报警机制
IP protocol - network segment division
2022 RoboCom 世界机器人开发者大赛-本科组(省赛)RC-u4 攻略分队 (已完结)
简化理解:发布订阅
Choice of advanced anti DDoS IP and CDN in case of DDoS
What is a firewall? What role can firewalls play?
C. Recover an RBS
R语言可视化分面图、多变量分组嵌套多水平t检验、并指定参考水平、可视化多变量分组嵌套多水平分面箱图(faceting boxplot)并添加显著性水平、指定显著性参考水平
Nine key measures to maintain server security in Hong Kong
Error in anyjson setup command: use_ 2to3 is invalid.
做好架构设计离不开SOLID五大原则
[adaptiveavgpool3d] pytorch tutorial
PyTorch的自动求导
JUC source code learning note 3 - AQS waiting queue and cyclicbarrier, BlockingQueue