【问题标题】:Query a list of Project numbers from a table of Projects via CRM Custom Plugin通过 CRM 自定义插件从项目表中查询项目编号列表
【发布时间】:2019-05-14 21:59:21
【问题描述】:

我在 CRM 中有一个项目实体表,每个项目实体都有一个名为“项目编号”的文本字段。我想查询出表中所有可用项目编号的列表。

我查看过的所有资源都提到我需要使用ServiceContextXrmServiceContext(),但似乎这些都是使用CrmSvcUtil 工具生成的。我用于这部分的教程位于here

根据我过去的 CRM 插件开发经验,I have found that I am not allowed to do any local tasks within the plugin execution,因此使用 CrmSvcUtil 工具与此冲突。

我处理这种情况完全错了吗?我可以访问OrganizationServiceContext,但我不确定这是否可以让我访问查询我的项目实体。

编辑:
下面列出了我的参考资料,但找不到 LocalPluginContext。快速谷歌搜索建议我只添加 sdk 中的项目,但我已经添加了所有内容。

【问题讨论】:

  • 您只是想手动查询数据,还是想针对它运行一些代码?如果是代码,是什么触发了它,它应该如何处理这些信息?
  • @Daryl 我希望我的插件在实体创建时触发(实体是一个项目),并且执行的管道阶段是 PreOperation。我这个插件的最终目标是自动为新创建的项目实体分配一个项目编号。项目编号生成器函数将使用查询列表作为输入来生成项目编号。项目编号由字母组成,字段类型为“文本行”。
  • LocalPluginContext 是文档中列出的示例上下文,但未在任何地方编译。

标签: c# plugins dynamics-crm dynamics-crm-2016


【解决方案1】:

有两种方法可以实现这一目标。 1.控制台应用程序,您不需要上下文,而是登录然后获取 IOrganizationService

static void Main(string[] args)
        {
            IOrganizationService organizationService = null;    
            try
            {
                ClientCredentials clientCredentials = new ClientCredentials();
                clientCredentials.UserName.UserName = "AdminCRM@dabc.onmicrosoft.com";
                clientCredentials.UserName.Password = "pwd";

                //For Dynamics 365 Customer Engagement V9.X, set Security Protocol as TLS12
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                //Get the URL from CRM, Navigate to Settings -> Customizations -> Developer Resources
                //Copy and Paste Organization Service Endpoint Address URL

                organizationService = (IOrganizationService)new OrganizationServiceProxy(new Uri("https:/[OrgUrl]/XRMServices/2011/Organization.svc"),
                    null, clientCredentials, null);

                if (organizationService != null)
                {
                    Guid userid = ((WhoAmIResponse)organizationService.Execute(new WhoAmIRequest())).UserId;

                    if (userid != Guid.Empty)
                    {
                        Console.WriteLine("Connection Established Successfully...");                          
                    FetchXmlTestQuery(organizationService);
                    queryExpressionTest(organizationService);    

                    }
                }
                else
                {
                    Console.WriteLine("Failed to Established Connection!!!");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception caught - " + ex.Message);
            }
            Console.ReadKey();    

        }

 private static void queryExpressionTest(IOrganizationService organizationService)
        {
            QueryExpression qe = new QueryExpression();
            qe.EntityName = "account";
            qe.ColumnSet= new ColumnSet("name", "accountnumber");

            EntityCollection coll = organizationService.RetrieveMultiple(qe);
            foreach (Entity acunt in coll.Entities)
            {
                Console.WriteLine("Name of Account: " + acunt.GetAttributeValue<string>("name"));
                Console.WriteLine("Number of Account: " + acunt.GetAttributeValue<string>("accountnumber"));
            }

        }


private static void FetchXmlTestQuery(IOrganizationService CrmConn)
        {
            // Retrieve all accounts owned by the user with read access rights to the accounts and   
            // where the last name of the user is not Cannon.   
            string fetch = @"  
   <fetch>
  <entity name='account' >
    <attribute name='name' />
<attribute name='accountnumber' />
    <link-entity name='contact' from='parentcustomerid' to='accountid' link-type='inner' alias='Contact' >
      <attribute name='fullname' alias = 'Contact.Fullname' />
    </link-entity>
  </entity>
</fetch> ";

           EntityCollection Coll = CrmConn.RetrieveMultiple(new FetchExpression(fetch));

                foreach (Entity acunt in Coll.Entities)
                {
                    Console.WriteLine("Name of Account: " + acunt.GetAttributeValue<string>("name"));
                    Console.WriteLine("Name of Contact: "  + acunt.GetAttributeValue<AliasedValue>("Contact.Fullname").Value);
                    Console.WriteLine("Number of Account: " + acunt.GetAttributeValue<string>("accountnumber"));
            }


        }

现在你也可以使用插件上下文了

protected override void ExecuteCrmPlugin(LocalPluginContext localContext)
        {
            if (localContext == null)
            {
                throw new ArgumentNullException("localContext");
            }

            // TODO: Implement your custom plug-in business logic.
            IPluginExecutionContext context = localContext.PluginExecutionContext;
            ITracingService tracingService = localContext.TracingService;
            IOrganizationService orgService = localContext.OrganizationService;

            FetchXmlTestQuery(orgService);
            queryExpressionTest(orgService);
}

 private void FetchXmlTestQuery(IOrganizationService orgService)
        {
            // Retrieve all accounts owned by the user with read access rights to the accounts and   
            // where the last name of the user is not Cannon.   
            string fetch = @"  
   <fetch>
  <entity name='account' >
    <attribute name='name' />
<attribute name='accountnumber' />
    <link-entity name='contact' from='parentcustomerid' to='accountid' link-type='inner' alias='Contact' >
      <attribute name='fullname' alias = 'Contact.Fullname' />
    </link-entity>
  </entity>
</fetch> ";

            EntityCollection Coll = orgService.RetrieveMultiple(new FetchExpression(fetch));

            foreach (Entity acunt in Coll.Entities)
            {
              string accountname= acunt.GetAttributeValue<string>("name");
             string accountnr=  acunt.GetAttributeValue<string>("accountnumber");
            }
        }
        private static void queryExpressionTest(IOrganizationService organizationService)
        {
            QueryExpression qe = new QueryExpression();
            qe.EntityName = "account";
            qe.ColumnSet = new ColumnSet("name", "accountnumber");

            EntityCollection coll = organizationService.RetrieveMultiple(qe);
            foreach (Entity acunt in coll.Entities)
            {
                string accountname = acunt.GetAttributeValue<string>("name");
                string accountnr =  acunt.GetAttributeValue<string>("accountnumber");
            }

        }

【讨论】:

  • ExecuteCrmPlugin 会取代通常与 Plugins 相关联的 Execute 函数吗?如果没有,我将如何获得 LocalPluginContext localContext?
  • 没关系。相当简单。 var localContext = new LocalPluginContext(serviceProvider);
  • 很高兴有帮助!如果您将其标记为已解决,那将会对其他人有所帮助。
  • 差不多了,你会知道LocalPluginContext 库与哪里相关联吗?我收到“找不到类型或命名空间名称‘LocalPluginContext’”错误。我将附上我上面所有引用的图片,这些图片都是从我的 sdk/bin 目录中提取的。
  • 感谢您的帮助。我没有通过开发工具包使用最后一个建议,但我能够使用 IServiceProvider 创建 IPluginExecutionContext、IOrganizationServiceFactory、IOrganizationService。话虽如此,我使用了建议的 XMLFetch 方法并成功返回了我的列表!
【解决方案2】:

在插件中,您将获得管道和组织服务访问的整个执行上下文,以在同一管道中扩展业务功能。

这些下面的代码 sn-ps 是样板代码,将为您提供各种必要的部分,例如用于日志记录的跟踪服务、获取目标实体的上下文、图像等以及 IOrganizationService 以进行更新、检索等服务调用实现平台扩展。

如您所知,Plugin 中将有一个公共类和一个公共方法 Execute(IServiceProvider serviceProvider),我们将使用这个单一参数 serviceProvider

获取所有内容
// Obtain the tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

// Obtain the execution context from the service provider.  
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

// Obtain the organization service reference which you will need for  
// web service calls.  
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

当您想从数据库中查询其他项目编号时,使用service.RetrieveMultiple方法查询。您可以传递 fetchxml 查询或使用 queryexpression 来完成。

你可以在网上找到很多例子。 Starter example.

【讨论】:

  • 再次感谢 Arun 将我指向 fetchxml 查询。不敢相信我忽略了这一点,让它变得更容易。
【解决方案3】:

这是我的推荐。

  1. 安装XrmToolBox(确保在解压缩之前解封压缩文件)
  2. 从工具中的 XrmToolBox 插件商店安装 Early Bound Generator 和 Visual Studio 解决方案加速器。
  3. 运行 Visual Studio 解决方案加速器,将核心项目添加到现有解决方案中,或使用它来创建新解决方案。我建议添加示例插件,以便您了解如何创建插件。还建议使用 EarlyBinding。
  4. 运行 EarlyBoundGenerator,粘贴从 Visual Studio 解决方案加速器复制到剪贴板的路径。添加插件所需的任何自定义实体。全部创建。
  5. 在插件项目中创建您的插件。

【讨论】:

    猜你喜欢
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 1970-01-01
    相关资源
    最近更新 更多