Dynamics365 自定义Action开发实例
前言
本文是为了完善之前写的Dynamics 365 按钮(二) 实例 - GongDonghai Blog (gdhblog.com)
,如果您一开始就看这篇文章的话可能看不明白,建议花几分钟瞄一下前面2篇文章。
Dynamics 365 按钮(一) 添加自定义按钮 - GongDonghai Blog (gdhblog.com)
Dynamics 365 按钮(二) 实例 - GongDonghai Blog (gdhblog.com)
在本文中,你将学会:
1.搭建项目
2.开发自定义Action
3.验证Action
1.创建Action
打开power apps -> 选择解决方案 -> 参考下图新建Action
填写显示名称,添加到选择“无”(“无”意思就是这是一个全局的Action)。
添加参数 -> 保存 -> 激活
2.新建项目(Visual Studio)
注:搭建项目的时候我习惯用Visual Studio的一个扩展插件创建(因为懒),你也可以不使用。
插件:
新建解决方案和项目
创建项目,下面截了创建插件项目操作步骤,请参考这个步骤创建WebResource项目。
然后再创建一个类库项目,我的解决方案项目如下:
添加EntityExtendAction.cs
添加SalesOrderItem.cs
添加ActionResultResponse.cs
(先新建Model文件夹,再添加ActionResultResponse.cs)
在插件项目添加如下包:
- ILMerge
- ILMerge.MSBuild.Task
添加完成后,设置插件项目引用的Microsoft.Xrm.SDK
"复制本地"属性设置为False
代码
ActionResultResponse.cs
namespace org40816cf4Sample.CRM.Plugins.Model
{
public class ActionResultResponse
{
public int status { get; set; }
public string msg { get; set; }
public dynamic data { get; set; }
}
}
EntityExtendAction.cs
using Microsoft.Xrm.Sdk;
using Newtonsoft.Json;
using org40816cf4Sample.CRM.BLL;
using org40816cf4Sample.CRM.Plugins.Model;
using System;
using System.Text.Json.Serialization;
namespace org40816cf4Sample.CRM.Plugins
{
public class EntityExtendAction : IPlugin
{
#region Secure/Unsecure Configuration Setup
private string _secureConfig = null;
private string _unsecureConfig = null;
public EntityExtendAction(string unsecureConfig, string secureConfig)
{
_secureConfig = secureConfig;
_unsecureConfig = unsecureConfig;
}
#endregion
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
IOrganizationService serviceAdmin = factory.CreateOrganizationService(null);
string _tag = context.InputParameters["tag"] as string;
string _arg = context.InputParameters["arg"] as string;
try
{
//TODO: Do stuff
string strResults = string.Empty;
if (_tag == "createsalesorderIteminvoice")
{
string outMsg = string.Empty;
SalesOrderItem logic = new SalesOrderItem(service, serviceAdmin);
bool b = logic.CreateSalesOrderItemInvoice(_arg,out outMsg);
ActionResultResponse actionResponse = new ActionResultResponse();
if (b)
{
actionResponse.status = 0;
}
else
{
actionResponse.status = 1;
actionResponse.msg = outMsg;
}
strResults = JsonConvert.SerializeObject(actionResponse);
}
context.OutputParameters["results"] = strResults;
}
catch (Exception e)
{
throw new InvalidPluginExecutionException(e.Message);
}
}
}
}
SalesOrderItem.cs
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
namespace org40816cf4Sample.CRM.BLL
{
/// <summary>
/// 销售订单
/// </summary>
public class SalesOrderItem
{
private dynamic _outputinfo = string.Empty;
private IOrganizationService service;
private IOrganizationService serviceAdmin;
public dynamic OutputInfo { get { return _outputinfo; } }
public SalesOrderItem(IOrganizationService _service)
{
service = _service;
serviceAdmin = _service;
}
public SalesOrderItem(IOrganizationService _service, IOrganizationService _serviceAdmin)
{
service = _service;
serviceAdmin = _serviceAdmin;
}
/// <summary>
/// 创建销售订单发票
/// </summary>
/// <param name="arg"></param>
/// <param name="outMsg"></param>
/// <returns></returns>
public bool CreateSalesOrderItemInvoice(string arg,out string outMsg)
{
outMsg = string.Empty;
if (string.IsNullOrEmpty(arg))
{
outMsg = "arg参数异常。";
return false;
}
string[] arr = arg.Split(';');
foreach (string id in arr)
{
Entity salesOrderItemEntity = service.Retrieve("gdh_sales_order_item", new Guid(id), new ColumnSet("gdh_dealer", "gdh_total_price"));
if (salesOrderItemEntity.Contains("gdh_dealer"))
{
EntityReference refDealer = salesOrderItemEntity.GetAttributeValue<EntityReference>("gdh_dealer");
Entity createInvoice = new Entity("gdh_sales_order_item_invoices");
createInvoice["gdh_dealer"] = new EntityReference(refDealer.LogicalName, refDealer.Id);
service.Create(createInvoice);
}
}
return true;
}
}
}
3.注册Action
1.打开插件注册工具PluginRegistration
如果没装有的,可以参考我之前写的这篇文章安装。
Dynamics 365 Dynamics 365 安装插件注册工具 PluginRegistration - GongDonghai Blog (gdhblog.com)
上传插件DLL文件
选择plugins项目编译成的dll文件
提示成功:
注册EntityExtendAction
Message选择前面我们在CRM系统创建Action时填写的唯一名称
可能遇到的问题:
1.为什么Message不显示/选不到“Action唯一名称”?
对应方法:①检查上面创建的Action是否激活,如果激活再做②; ②关掉插件注册工具,再尝试注册EntityExtendAction
以上就完成了本次示例使用的Action了,后面我们回到Dynamics 365 按钮(二) 实例 - GongDonghai Blog (gdhblog.com)修改一下SalesOrderItem.js
,调用Action。
4.验证/调用Action
我们使用:CRM REST BUILDER
调用,如果没有安装的话可以参考这篇文章进行安装:
Dynamics 365 DYNAMICS CRM REST BUILDER - GongDonghai Blog (gdhblog.com)
tag
: createsalesorderIteminvoice
arg
:c0922ae9-465b-ee11-be6f-0017fa06c679;b1371fe3-465b-ee11-be6f-0017fa06c679
温馨提示:arg是我自己记录的id,不要盲目copy。
点击【Create Request】
点击【Execute Code】
调用成功,状态返回0。
5.补充说明
1.为什么我要分DLL、Plugins、WebResource?
项目需要自定义开发多时方便代码管理。
DLL:某个实体的功能,比如合同实体需要自定义添加一些功能,那么我会在DLL添加一个Contract.cs
类,在该类写方法,供插件调用。
Plugins:还是以合同实体需要添加自定义功能为例,比如插件触发点是合同记录创建前、合同记录创建后,那么我会在Plugins分别添加两个类:
ContractPreCreate.cs
ContractPostCreate.cs
WebResource:主要放Javascript
2.为什么Action参数是tag、arg、results?
这是个人习惯,你可以根据自己的需求进行调整。一般地,我习惯将自定义开发的Action放到EntityExtendAction.cs
里,然后各类实体调用的话用tag
进行区分。
3.为什么要在插件项目安装包 ILMerge、ILMerge.MSBuild.Task ?
因为插件项目引用了DLL项目,在插件工具新建Assembly
时会报错(具体错误忘记截图了),所以用到,其目的是将dll或者exe合并在一起。
以上。
2 条评论
[...]前言如果你没添加过自定义按钮,自定义Action,建议花两杯茶时间看下前几篇:Dynamics 365 按钮(一) 添加自定义按钮 - GongDonghai Blog (gdhblog.com)Dynamics 365 按钮(二) 实例 - GongDonghai Blog (gdhblog.com)Dynamics 365 自定义Action开发实例 - GongDonghai Blog (g[...]
[...]}更新SalesOrderItem.js后验证下是否能取到所选记录的id:可以取到的,接下来我们在写一个Action,Action我另外再写一篇:Dynamics 365 自定义Action开发实例 - GongDonghai Blog (gdhblog.com)写好Action后,我们再调整一下CreateSalesOrderItemInvoice方法:CreateSalesOrderItemI[...]