关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复239或者20161203可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me 。

以前我出过一个悬赏题目,就是定制Dynamics CRM标准的导出功能,让某些列不能导出,比如这些列可能包括敏感信息,比如消费者的姓名和电话等等,如何定制呢?我到现在还没有收到答案。某个周末的晚上,我研究了一下,初步有些效果,所以本博文记下来。
最容易想到的是注册插件,与导出有关的消息至少有四个,分别是Export, ExportAll, ExportCompressed 和ExportCompressedAll,可是注册在这四个消息上不管用。于是想到了在RetrieveMultiple消息上动刀,这个消息经常使用,除了根据主键和备用键查询数据以外,应该都是通过这个消息查询数据,导出也要查询数据。可是如果每次查询数据都执行的话,很消耗性能,后来我发现导出的时候执行的这个消息和普通的查询似乎有一个区别,就是导出的时候执行这个消息的上下文的Depth属性值为2,所以可以利用这个属性做点文章,尽量少执行点代码。
我先使用如下代码来查看打开一个普通的视图,插件中获取的各种参数,我这个代码是注册在罗勇测试实体RetrieveMultiple的Pre阶段。
using System;
using Microsoft.Xrm.Sdk;
using System.Text;
using Microsoft.Xrm.Sdk.Query;
using System.Linq;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;namespace CrmVSSolution.Plugins
{public class PreTestRetrieveMultiple : IPlugin{public void Execute(IServiceProvider serviceProvider){// Extract the tracing service for use in debugging sandboxed plug-ins.// If you are not registering the plug-in in the sandbox, then you do// not have to add any tracing service related code.ITracingService tracingService =(ITracingService)serviceProvider.GetService(typeof(ITracingService));// Obtain the execution context from the service provider.IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));IOrganizationServiceFactory serviceFactory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);StringBuilder sb = new StringBuilder();sb.Append("Depth=");sb.Append(context.Depth);sb.Append(";PrimaryEntityName=");sb.Append(context.PrimaryEntityName);sb.Append(";PrimaryEntityId=");sb.Append(context.PrimaryEntityId);sb.Append(";BusinessUnitId=");sb.Append(context.BusinessUnitId);sb.Append(";InitiatingUserId=");sb.Append(context.InitiatingUserId);sb.Append(";IsExecutingOffline");sb.Append(context.IsExecutingOffline);sb.Append(";IsInTransaction=");sb.Append(context.IsInTransaction);sb.Append(";IsOfflinePlayback=");sb.Append(context.IsOfflinePlayback);sb.Append(";IsolationMode=");sb.Append(context.IsolationMode);sb.Append(";MessageName=");sb.Append(context.MessageName);sb.Append(";OperationId=");sb.Append(context.OperationId);sb.Append(";OrganizationId=");sb.Append(context.OrganizationId);sb.Append(";OrganizationName=");sb.Append(context.OrganizationName);sb.Append(";OutputParameters=");if (context.OutputParameters != null){sb.Append("{");foreach (var outputpara in context.OutputParameters){sb.Append(outputpara.Key);sb.Append("=");sb.Append(outputpara.Value.ToString());}sb.Append("}");}else{sb.Append("null");}sb.Append(";OwningExtension=");if (context.OwningExtension != null){sb.Append("{LogicalName=");sb.Append(context.OwningExtension.LogicalName);sb.Append(";Name=");sb.Append(context.OwningExtension.Name);sb.Append(";Id=");sb.Append(context.OwningExtension.Id);}else{sb.Append("null");}sb.Append(";ParentContext=");if (context.ParentContext != null){sb.Append(context.ParentContext.ToString());}else{sb.Append("null");}sb.Append(";PostEntityImages=");if (context.PostEntityImages != null){sb.Append("{");foreach (var postimg in context.PostEntityImages){sb.Append("Key=");sb.Append(postimg.Key);sb.Append(";Value.Id=");sb.Append(postimg.Value.Id);sb.Append(";Value.LogicalName=");sb.Append(postimg.Value.LogicalName);foreach (var attr in postimg.Value.Attributes){sb.Append("Attr=");sb.Append(attr.Key);sb.Append(";Value=");sb.Append(attr.Value.ToString());}}sb.Append("}");}else{sb.Append("null");}sb.Append(";PreEntityImages=");if (context.PreEntityImages != null){sb.Append("{");foreach (var preimg in context.PreEntityImages){sb.Append("Key=");sb.Append(preimg.Key);sb.Append(";Value.Id=");sb.Append(preimg.Value.Id);sb.Append(";Value.LogicalName=");sb.Append(preimg.Value.LogicalName);foreach (var attr in preimg.Value.Attributes){sb.Append("Attr=");sb.Append(attr.Key);sb.Append(";Value=");sb.Append(attr.Value.ToString());}}sb.Append("}");}else{sb.Append("null");}sb.Append(";SecondaryEntityName=");sb.Append(context.SecondaryEntityName);sb.Append(";RequestId=");sb.Append(context.RequestId.HasValue ? context.RequestId.Value.ToString() : "null");sb.Append(";Stage=");sb.Append(context.Stage);sb.Append(";UserId=");sb.Append(context.UserId);sb.Append(";InputParameters=");if (context.InputParameters != null){sb.Append("{");foreach (var inputpara in context.InputParameters){sb.Append(inputpara.Key);sb.Append("=");sb.Append(inputpara.Value.ToString());if (inputpara.Key == "Query"){var queryexp = inputpara.Value as QueryExpression;sb.Append("ColumnSet={");foreach (var col in queryexp.ColumnSet.Columns){sb.Append(col);sb.Append(",");}sb.Append("}");sb.Append("LinkEntities={");if (queryexp.LinkEntities != null){sb.Append("LinkEntity={");foreach (var linkentity in queryexp.LinkEntities.Where(x => x.LinkToEntityName == "ly_test")){sb.Append("LinkToEntityName=");sb.Append(linkentity.LinkToEntityName);sb.Append(";LinkFromEntityName=");sb.Append(linkentity.LinkFromEntityName);sb.Append(";LinkColumnSet={");sb.Append(string.Join(",", linkentity.Columns.Columns));sb.Append("}");}sb.Append("}");}else{sb.Append("null");}sb.Append("}");}}sb.Append("}");}else{sb.Append("null");}sb.Append("当前用户拥有角色:");sb.Append(string.Join(",", GetUserRoles(service, context.UserId)));if (context.InputParameters.Contains("Query") && context.InputParameters["Query"] is QueryExpression){//throw new InvalidPluginExecutionException("不是管理员不能导出!");//这个错误提示不会展示在前台给用户看到QueryExpression objQueryExpression = (QueryExpression)context.InputParameters["Query"];sb.Append("查找的主实体是:");sb.Append(objQueryExpression.EntityName);sb.Append("查询表达式是:");XmlSerializer xmlSerializer = new XmlSerializer(objQueryExpression.GetType());using (StringWriter textWriter = new StringWriter()){xmlSerializer.Serialize(textWriter, objQueryExpression);sb.Append(textWriter.ToString());}}var entity = new Entity("annotation");entity["subject"] = "execute retrievemultiple";entity["objectid"] = new EntityReference("ly_test", Guid.Parse("B707DE1B-CF99-E611-8161-000D3A80C8B8"));entity["notetext"] = sb.ToString();service.Create(entity);}public IEnumerable<string> GetUserRoles(IOrganizationService service, Guid userId){string fetchXml = string.Format(@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true' no-lock='true'>
<entity name='role'>
<attribute name='name' />
<link-entity name='systemuserroles' from='roleid' to='roleid' visible='false' intersect='true'>
<link-entity name='systemuser' from='systemuserid' to='systemuserid' alias='ad'>
<filter type='and'>
<condition attribute='systemuserid' operator='eq' value='{0}' />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>", userId);EntityCollection entities = service.RetrieveMultiple(new FetchExpression(fetchXml));return entities.Entities.Select(x => x.GetAttributeValue<string>("name"));}}
}

得到的结果如下:
Depth=1;PrimaryEntityName=ly_test;PrimaryEntityId=00000000-0000-0000-0000-000000000000;BusinessUnitId=487cdd4b-26a3-e511-80c6-000d3a807ec7;InitiatingUserId=e9cd027f-26a3-e511-80c6-000d3a807ec7;IsExecutingOffline:False;IsInTransaction=False;IsOfflinePlayback=False;IsolationMode=2;MessageName=RetrieveMultiple;OperationId=00000000-0000-0000-0000-000000000000;OrganizationId=bd2a5c49-6b08-4eda-8a15-84159d9fd349;OrganizationName=Demo;OutputParameters={};OwningExtension={LogicalName=sdkmessageprocessingstep;Name=CrmVSSolution.Plugins.PreTestRetrieveMultiple: RetrieveMultiple of ly_test;Id=544ba42f-baae-e611-816e-000d3a80c8b8;ParentContext=null;PostEntityImages={};PreEntityImages={};SecondaryEntityName=none;RequestId=null;Stage=20;UserId=e9cd027f-26a3-e511-80c6-000d3a807ec7;InputParameters={Query=Microsoft.Xrm.Sdk.Query.QueryExpressionColumnSet={ly_name,modifiedon,ly_minutessincecreated,createdon,ly_testid,processid,ly_name,ly_minutessincecreated,modifiedon,createdon,}LinkEntities={LinkEntity={}}}当前用户拥有角色:System Customizer,计划经理,计划员,系统管理员;查找的主实体是:ly_test;查询表达式是:<?xml version="1.0" encoding="utf-16"?>
<QueryExpression _tmplitem="3" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionData _tmplitem="3" ></ExtensionData>
<Distinct _tmplitem="3" >false</Distinct>
<NoLock _tmplitem="3" >true</NoLock>
<PageInfo _tmplitem="3" >
<PageNumber _tmplitem="3" >1</PageNumber>
<Count _tmplitem="3" >50</Count>
<ReturnTotalRecordCount _tmplitem="3" >true</ReturnTotalRecordCount>
<ExtensionData _tmplitem="3" ></ExtensionData>
</PageInfo>
<LinkEntities _tmplitem="3" >
<LinkEntity _tmplitem="3" >
<LinkFromAttributeName _tmplitem="3" >processid</LinkFromAttributeName>
<LinkFromEntityName _tmplitem="3" >ly_test</LinkFromEntityName>
<LinkToEntityName _tmplitem="3" >workflow</LinkToEntityName>
<LinkToAttributeName _tmplitem="3" >workflowid</LinkToAttributeName>
<JoinOperator _tmplitem="3" >LeftOuter</JoinOperator>
<LinkCriteria _tmplitem="3" >
<FilterOperator _tmplitem="3" >And</FilterOperator>
<Conditions _tmplitem="3" ></Conditions>
<Filters _tmplitem="3" ></Filters>
<IsQuickFindFilter _tmplitem="3" >false</IsQuickFindFilter>
<ExtensionData _tmplitem="3" ></ExtensionData>
</LinkCriteria>
<LinkEntities _tmplitem="3" />
<Columns _tmplitem="3" >
<AllColumns _tmplitem="3" >false</AllColumns>
<Columns _tmplitem="3" >
<string _tmplitem="3" >versionnumber</string>
</Columns>
<ExtensionData _tmplitem="3" ></ExtensionData>
</Columns>
<EntityAlias _tmplitem="3" >processidworkflowworkflowid</EntityAlias>
<Orders _tmplitem="3" ></Orders>
<ExtensionData _tmplitem="3" ></ExtensionData>
</LinkEntity>
</LinkEntities>
<Criteria _tmplitem="3" >
<FilterOperator _tmplitem="3" >And</FilterOperator>
<Conditions _tmplitem="3" ></Conditions>
<Filters _tmplitem="3" ></Filters>
<IsQuickFindFilter _tmplitem="3" >false</IsQuickFindFilter>
<ExtensionData _tmplitem="3" ></ExtensionData>
</Criteria>
<Orders _tmplitem="3" >
<OrderExpression _tmplitem="3" >
<AttributeName _tmplitem="3" >ly_name</AttributeName>
<OrderType _tmplitem="3" >Ascending</OrderType>
<ExtensionData _tmplitem="3" ></ExtensionData>
</OrderExpression>
</Orders>
<EntityName _tmplitem="3" >ly_test</EntityName>
<ColumnSet _tmplitem="3" >
<AllColumns _tmplitem="3" >false</AllColumns>
<Columns _tmplitem="3" >
<string _tmplitem="3" >ly_name</string>
<string _tmplitem="3" >modifiedon</string>
<string _tmplitem="3" >ly_minutessincecreated</string>
<string _tmplitem="3" >createdon</string>
<string _tmplitem="3" >ly_testid</string>
<string _tmplitem="3" >processid</string>
<string _tmplitem="3" >ly_name</string>
<string _tmplitem="3" >ly_minutessincecreated</string>
<string _tmplitem="3" >modifiedon</string>
<string _tmplitem="3" >createdon</string>
</Columns>
<ExtensionData _tmplitem="3" ></ExtensionData>
</ColumnSet>
<TopCount _tmplitem="3" xsi:nil="true" ></TopCount>
</QueryExpression>

然后到主题了,我这假设限制罗勇测试实体的十进制数列(ly_decimal)不允许导出,就在这个实体的RetrieveMultiple消息的Pre阶段使用如下代码,当然我还做了个限制,没有系统管理员角色不能导出,只是为了证明这里面可以做很多事情,用权限来控制导出功能,很简单吧:
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Linq;
using System.Collections.Generic;namespace CrmVSSolution.Plugins
{public class PreTestRetrieveMultiple : IPlugin{public void Execute(IServiceProvider serviceProvider){ITracingService tracingService =(ITracingService)serviceProvider.GetService(typeof(ITracingService));IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));IOrganizationServiceFactory serviceFactory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);//context.Depth = 2是导出的时候执行if (context.Depth == 2 && context.InputParameters.Contains("Query") && context.InputParameters["Query"] is QueryExpression){if (!GetUserRoles(service, context.UserId).Contains("系统管理员")){throw new InvalidPluginExecutionException("不是管理员不能导出!");//这个错误提示不会展示在前台给用户看到
                }QueryExpression objQueryExpression = (QueryExpression)context.InputParameters["Query"];objQueryExpression.ColumnSet = new ColumnSet(objQueryExpression.ColumnSet.Columns.Where(col => col != "ly_decimal").ToArray());}}public IEnumerable<string> GetUserRoles(IOrganizationService service, Guid userId){string fetchXml = string.Format(@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true' no-lock='true'>
<entity name='role'>
<attribute name='name' />
<link-entity name='systemuserroles' from='roleid' to='roleid' visible='false' intersect='true'>
<link-entity name='systemuser' from='systemuserid' to='systemuserid' alias='ad'>
<filter type='and'>
<condition attribute='systemuserid' operator='eq' value='{0}' />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>", userId);EntityCollection entities = service.RetrieveMultiple(new FetchExpression(fetchXml));return entities.Entities.Select(x => x.GetAttributeValue<string>("name"));}}
}

在界面上可以看到十进制数列有值:
导出来的时候这个列就没有值:
这样虽然可以导出罗勇测试实体的时候不到处十进制字段,但是我如果查询的是它的子实体,然后加上这个实体的十进制字段显示,这个用高级查找很容易做到,导出的话就可以看到这个列了。
这个时候我需要在这个实体的1:N关系的子实体中也在RetrieveMultiple消息的Pre阶段注册类似如下插件代码即可:
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Linq;namespace CrmVSSolution.Plugins
{public class PreTestSubRetrieveMultiple : IPlugin{public void Execute(IServiceProvider serviceProvider){ITracingService tracingService =(ITracingService)serviceProvider.GetService(typeof(ITracingService));IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));IOrganizationServiceFactory serviceFactory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);//context.Depth=2是导出的时候执行if (context.Depth == 2 && context.InputParameters.Contains("Query") && context.InputParameters["Query"] is QueryExpression){QueryExpression objQueryExpression = (QueryExpression)context.InputParameters["Query"];if (objQueryExpression.LinkEntities != null) //当这个不能导出的实体作为关联的父实体加入了视图列,也需要过滤
                {foreach (var linkentity in objQueryExpression.LinkEntities.Where(x => x.LinkToEntityName == "ly_test")){linkentity.Columns = new ColumnSet(linkentity.Columns.Columns.Where(col => col != "ly_decimal").ToArray());}}}}}
}

然后我可以看到效果,这个列的值导不出来了。

当然可能还有其他方法可以导出,我说的利用标准的功能不需要开发,欢迎各位看官提出来,看看能否封堵住。

转载于:https://www.cnblogs.com/luoyong0201/p/Dynamics_365_Customize_Export_Excel_Function_Forbidden_Export_Field_Value.html

定制Dynamics CRM标准导出功能:不能导出指定列的值相关推荐

  1. java Excel导出功能之 不固定列表格

    背景:考勤周期为本月19号至上月20号,则每个月考勤周期表的列是动态变化的.所有数据显示和excel导出功能都需要动态的进行处理. 显示格式如下图 前端 checkin.jsp<%@ page ...

  2. Android 12适配安全组件导出设置`android:exported` 指定显式值”

    如何解决编译错误:"面向 Android 12 及更高版本的应用需要为 android:exported 指定显式值"问题 如果您的应用针对 Android12,则文档说: 如果您 ...

  3. Microsoft Dynamics CRM 2015 新增功能 介绍 高级查找功能

    查找功能. 非常强大,右上角为高级查找功能 高级查找,改进的搜索功能为用户提供了一种可以在 Web 应用程序的多个记录类型中的快速搜索方式.现在,通过在导航栏的搜索框中输入关键字,您可以在 Web 应 ...

  4. C# 开发dynamics crm修改密码功能

    asp.net站点实现,话不多说,先上核心代码, 简单界面如下如所示: <%@ Page Title="Home Page" Language="C#" ...

  5. excel自动导出功能_自动关联数据字典---SpringCloud Alibaba_若依微服务框架改造---工作笔记008

    若依框架自动生成的页面,有数据导出功能,可以导出excel, 但是对于带有数据字典的字段来说,比如男女,0是男,1是女 那么这个时候,导出的excel中就会显示出来.0,1而不会显示出来 汉字,男,女 ...

  6. java实现Word 文档形式的导出功能

    关于在Java中实现导出功能,导出格式为Word文档导出,具体参考如下代码. 1 先准备好一个导出Word文档的模板. 例如: 将其存值地方用字段代替.例如: 2.打开doc文件后 ,文件中的另存为, ...

  7. Java解析xml文件dom4j篇(基于xml配置文件完成Excel数据的导入、导出功能完整实现)

    DOM4J解析XML文件 dom4j是一个Java的XML API,是jdom的升级产品,用来读写XML文件.另外对比其他API读写XML文件,dom4j是一个十分优秀的JavaXML API,具有性 ...

  8. Dynamics CRM 2016 的新特性

    新版本CRM (2016 with update 0.1)发布已有几个月了,总结一下新特性,从几个方面来看: 1.针对整合功能的新特性 (1) 增加了CRM App for Outlook. 这个是一 ...

  9. Dynamics CRM 无法导出数据

    当Dynamics CRM 用标准功能无法导出数据时,需要考虑导出的视图是否有相同的字段名称.这与导入时的要求一样,不可以有相同的字段名称.

最新文章

  1. 浅显易懂讲讲网关和DNS的概念—Vecloud微云
  2. java 自省_自知 自省 自立 自信 自尊 自治 自强 自制
  3. *【CodeForces - 280C】Game on Tree(期望模型,期望的线性性)
  4. java工程师要懂哪些东西_Java工程师都需要懂哪些知识?学实用知识得高薪
  5. [转]JS弹出div和关闭
  6. linux kill
  7. android模拟器电视,AndroidTV 模拟器的搭建
  8. 【Java】接口.案例.打印机
  9. PMP-五大项目管理过程组
  10. [转]NLP关键词提取方法总结及实现
  11. 参考答案-数据库原理测试一
  12. Java为什么要有基本数据类型和包装类型
  13. Python 协议攻击脚本(六): STP攻击
  14. 区分Linux中的“根目录”和“家目录”
  15. 大虾救命啊~~~~~~~~~~
  16. Huawei U8825d 对4G手机内存重新分区过程[把2Gb内置SD卡容量划分给DATA分区使用]...
  17. CNN经典之VGG网络+PyTorch复现
  18. 双面铣组合机床设计(全套优秀毕业设计含CAD图纸、说明书)
  19. GPS 校验和 代码_浙江国产安全阀校验台批发价-欧迪美特ODMT
  20. 智慧校园下“企业微信+CAS”的统一身份认证方案设计

热门文章

  1. 基于Android系统的IPv6网络接入分析
  2. JavaScript对象的理解
  3. java中限制多人登录的_Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析...
  4. 【lib.es5】ArrayBuffer、DataView 的TypeScript接口
  5. 闭包 python_Python闭包思想与用法浅析
  6. AcWing 4. 多重背包问题(多重背包 朴素版)
  7. mysql 执行计划 改变_数据量增加导致mysql执行计划改变解决_MySQL
  8. OpenCV基本图形绘制之椭圆
  9. 发生冲突未及时离场 绿军大将被NBA罚款3.5万美元
  10. PetShop 4.0知识点:加密和解密Web.config文件的配置节