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

创建Action1.png

填写显示名称,添加到选择“无”(“无”意思就是这是一个全局的Action)。

创建Action2.png

添加参数 -> 保存 -> 激活

创建Action3.png

2.新建项目(Visual Studio)

注:搭建项目的时候我习惯用Visual Studio的一个扩展插件创建(因为懒),你也可以不使用。

插件:

image.png

新建解决方案和项目

创建项目,下面截了创建插件项目操作步骤,请参考这个步骤创建WebResource项目

image.png

然后再创建一个类库项目,我的解决方案项目如下:

image.png

添加EntityExtendAction.cs

image.png

image.png

添加SalesOrderItem.cs

image.png

image.png

添加ActionResultResponse.cs

(先新建Model文件夹,再添加ActionResultResponse.cs)

image.png


在插件项目添加如下包:

  • ILMerge
  • ILMerge.MSBuild.Task

image.png

添加完成后,设置插件项目引用的Microsoft.Xrm.SDK"复制本地"属性设置为False

image.png


代码

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文件

image.png

选择plugins项目编译成的dll文件

image.png

提示成功:

image.png

注册EntityExtendAction

image.png

Message选择前面我们在CRM系统创建Action时填写的唯一名称

image.png

可能遇到的问题:

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)

image.png

tag : createsalesorderIteminvoice

arg:c0922ae9-465b-ee11-be6f-0017fa06c679;b1371fe3-465b-ee11-be6f-0017fa06c679

温馨提示:arg是我自己记录的id,不要盲目copy。

点击【Create Request】

image.png

点击【Execute Code】

image.png

调用成功,状态返回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合并在一起

以上。

最后修改:2023 年 10 月 10 日
如果觉得我的文章对你有用,请随意赞赏