从Dynamics 365 for Customer Engagement 9.0开始,虚实体通过在Dynamics 365 Customer Engagement中无缝地将数据表示为实体,实现了外部系统中的数据集成。它无需数据复制,通常也无需自定义编码。
虚实体有如下的限制,但除了下面的这些限制外,它和其它的那些自定义实体没有区别:
- 数据是只读的。虚实体特性不支持在 Dynamics 365中 CE所做的更改在推回到外部系统
- 只支持实体的组织级权限。不支持字段级安全
- 对于外部数据,需要抽象建模为D365的支持的那些字段,就比如说你想获取外部系统中一条记录的姓名,性别,年龄字段,那么在虚实体中,你需要创建与姓名,性别和年龄字段相符的字段类型,比如text, number, optionset, date, image, 和lookup类型
- 外部数据的记录必须有一个GUID格式的主键与虚实体中的主键相关联
- 无法使用计算字段,如果需要计算,需要在外部系统完成或者在data provider中进行处理。
- 无法筛选某一列的值或者进行对其进行排序
- 不支持Audit History
- 不能为queue启用虚实体
- 虚实体不支持BPF
- 虚实体一旦创建就不能更改为普通实体
1. 创建插件并注册
这个插件将会实现Retrieve和Retrieve Multiple,示例代码中是连接到另外一个组织的D365中,获取Account实体里的记录并显示出来.
将这些hardcode写到你的插件中并不是一个很好的方法,我这样做主要是为了让你可以更容易看到它是如何工作的,你在编写自己的代码的时候需要将这些配置信息妥善处理一下
对于如何下面代码中的这些配置信息在Azure中的什么地方能够找到,大家可以参考下面的这篇博客
Dynamics 365: 如何从Azure中获取连接到D365 Online所需要的认证信息_Stone-hdj的博客-CSDN博客https://blog.csdn.net/djstone/article/details/124927079?spm=1001.2014.3001.5502
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 = "applicationuser@XXXX.onmicrosoft.com";
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 = "applicationuser@XXXX.onmicrosoft.com";
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);
}
}
}
}
需要注意上面的代码中用到了Newtonsoft这个第三方的Nuget包,所以我们需要使用ILMerge或者Costura.Fody来打包成一个dll.
注册插件(不需要注册step,后续创建Data Provider的时候会自动添加MainOperation这个step)
2. 注册Data Provider
Plugin Registeration Tool: Register -> Register New Data Provider
Solution: 这里我们选择新建一个solution, 它里面会放我们下面填的Data Source Entity(虚实体)
Data Source Entity:选择新建一个data source
Assembly: 选择我们刚刚注册的插件
Retrieve和Retrieve Multiple:也是选择我们我们刚刚创建的
注册完成后我们会看到,第一步我们创建的插件里的就会被自动填充步骤
并且我们发现里面的步骤都是不可编辑的
3. 系统内部新建Data Source
Setting -> Administration -> Virtual Entity Data Sources
选择我们上面第二步创建的Data Provider
填写Name并保存
4. 创建虚实体
实体里需要把Virtual Entity选中,Data Source选择我们刚刚创建的数据源
Note:这一步里的字段需要和上面代码里的是对应上的,如下图
5. 效果
我们使用高级查找去测试一下,高级查找会调用Retrieve Multiple
因为我们代码中做了过滤,只提取A开头的Account
当我们点击其中一条记录来打开,它会调用Retrieve
参考链接:文章来源:https://www.toymoban.com/news/detail-464907.html
Get started with virtual entities (Developer Guide for Dynamics 365 Customer Engagement) | Microsoft Docshttps://docs.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/virtual-entities/get-started-ve?view=op-9-1#limitations-of-virtual-entities使用自定义数据源配置虚拟实体 - 微软MVP(15-18)罗勇 - 博客园 (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/文章来源地址https://www.toymoban.com/news/detail-464907.html
到了这里,关于Dynamics 365: 详解虚实体(Virtual Entity) 从0到1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!