<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_石头居</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/54944/rss</id><updated>2012-04-04T14:44:38Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/54944/rss"/><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/03/22/2411499.html</id><title type="text">MS CRM 2011的自定义与开发(12)&amp;mdash;&amp;mdash;表单脚本扩展开发(5)</title><summary type="text">之前的两篇文章，介绍了Microsoft Dynamics CRM 2011开发中表单脚本的数据管理器Xrm.Page.data方面的内容，下面介绍UI管理器Xrm.Page.ui方面的内容。 X...</summary><published>2012-03-22T05:39:00Z</published><updated>2012-03-22T05:39:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/22/2411499.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/22/2411499.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 之前的两篇文章，介绍了Microsoft Dynamics CRM 2011开发中表单脚本的数据管理器Xrm.Page.data方面的内容，下面介绍UI管理器Xrm.Page.ui方面的内容。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.ui对象包括了两大类内容：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;第一类，是一组方法，用于获取当前用户界面中的信息；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;第二类，是一些集合，这些集合对应了一组组的界面上同类界面元素。&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面，首先说一下获取UI信息的方法&lt;/p&gt; &lt;table border="1" cellspacing="1" cellpadding="2" width="800"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt; &lt;p align="center"&gt;&lt;strong&gt;方法&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="650"&gt; &lt;p align="center"&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;close&lt;/td&gt; &lt;td valign="top" width="650"&gt;关闭当前表单。&lt;br&gt;使用方法Xrm.Page.ui.close()&lt;br&gt;注意：尽量不要使用window.close()方法关闭表单，而应该使用Xrm.Page.ui.close()方式关闭表单，因为使用这种方式关闭表单，对于用户修改过表单中某些字段值的情况下，系统会弹出提示，是否进行保存。&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;getCurrentControl&lt;/td&gt; &lt;td valign="top" width="650"&gt;获取当前获得焦点的界面元素控件&lt;br&gt;使用方法Xrm.Page.ui.getCurrentControl();&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;getFormType&lt;/td&gt; &lt;td valign="top" width="650"&gt;获取记录的表单上下文，换言之，获取表单的类型&lt;br&gt;使用方法Xrm.Page.getFormType();&lt;br&gt;表单类型对应了当前记录的不同状态，对应列表如下：&lt;br&gt; &lt;table border="1" cellspacing="1" cellpadding="1" width="638"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt; &lt;p align="center"&gt;表单类型值&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="462"&gt; &lt;p align="center"&gt;表单类型&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;0&lt;/td&gt; &lt;td valign="top" width="462"&gt;未定义&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;1&lt;/td&gt; &lt;td valign="top" width="462"&gt;创建，点击“新建”按钮，系统弹出的表单&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;2&lt;/td&gt; &lt;td valign="top" width="462"&gt;更新，编辑某条记录时，弹出的表单&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;3&lt;/td&gt; &lt;td valign="top" width="462"&gt;只读，只有只读权限的用户打开记录时的表单&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;4&lt;/td&gt; &lt;td valign="top" width="462"&gt;禁用，打开处于禁用状态的记录的表单&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;5&lt;/td&gt; &lt;td valign="top" width="462"&gt;快速创建（已经弃用）&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="176"&gt;6&lt;/td&gt; &lt;td valign="top" width="462"&gt;批量编辑&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;getViewPortHeight&lt;/td&gt; &lt;td valign="top" width="650"&gt;获取视口（viewport）的高度&lt;br&gt;使用方法Xrm.Page.ui.getViewPortHeight()&lt;br&gt;所谓视口viewport，也就是包含表单数据的页面区域，对应了表单的正文body部分，而不包括导航区、标题区和页脚区，以及表单帮助区&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;getViewPortWidth&lt;/td&gt; &lt;td valign="top" width="650"&gt;获取视口（viewport）的宽度&lt;br&gt;使用方法Xrm.Page.ui.getViewPortWidth()&lt;br&gt;所谓视口viewport，也就是包含表单数据的页面区域，对应了表单的正文body部分，而不包括导航区、标题区和页脚区，以及表单帮助区&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="150"&gt;refreshRibbon&lt;/td&gt; &lt;td valign="top" width="650"&gt;刷新表单上的Ribbon工具条，从而强制系统重新计算、评估以确定Ribbon工具条中的内容&lt;br&gt;使用方法Xrm.Page.ui.refreshRibbon();&lt;br&gt;注意：这个方法主要用在了Ribbon中的EnableRule规则元素中，当该规则元素将表单某个字段值作为判断依据时，当脚本代码更改了字段值之后，使用refreshRibbon()方法，强制系统重新计算，从而刷新Ribbon工具条显示效果&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2411499.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/22/2411499.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/03/20/2408082.html</id><title type="text">MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(4)</title><summary type="text">除了在上一篇文章中介绍的Xrm.Page.data.entity对象本身包含的方法之外，Xrm.Page.data.entity对象还包含一个当前实体记录所有属性的集合，名为Xrm.Page.dat...</summary><published>2012-03-20T08:04:00Z</published><updated>2012-03-20T08:04:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/20/2408082.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/20/2408082.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 除了在&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/18/2404625.html" target="_blank"&gt;上一篇文章&lt;/a&gt;中介绍的Xrm.Page.data.entity对象本身包含的方法之外，Xrm.Page.data.entity对象还包含一个当前实体记录所有属性的集合，名为Xrm.Page.data.entity.attributes，其中包含了表单中所有字段的信息。同时，对每个字段，根据其数据类型的不同，Microsoft Dynamics CRM也提供了相应的一组方法进行操纵、管理与控制。&lt;/p&gt;&lt;table style="width: 800px;" border="1" cellspacing="1" cellpadding="2"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;&lt;p align="center"&gt;&lt;strong&gt;方法&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top" width="769"&gt;&lt;p align="center"&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top" width="202"&gt;&lt;p align="center"&gt;&lt;strong&gt;适用的字段类型&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;addOnChange&lt;/td&gt;&lt;td valign="top" width="769"&gt;输入参数为方法指针，添加字段OnChange事件的处理函数&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;fireOnChange&lt;/td&gt;&lt;td valign="top" width="769"&gt;触发相应字段的OnChange事件，以执行该字段的OnChange事件的处理函数&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getAttributeType&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的数据类型，返回值为字符串，根据字段的数据类型不同，返回值可以是："boolean"、"datetime"、"decimal"、"double"、"integer"、"lookup"、"memo"、"money"、&lt;br /&gt;"optionset"、"string"&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getFormat&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的格式化选项，返回值为字符串&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getInitialValue&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取在表单打开时，bool类型或者OptionSet类型字段的初始值，返回值是数字&lt;/td&gt;&lt;td valign="top" width="202"&gt;bool、OptionSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getIsDirty&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取一个bool值，以标明特定的字段在本次表单打开后，该字段值是否曾经被更改过&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getMax&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取特定类型字段（money、decimal、integer、double）的最大值，返回值为数字&lt;/td&gt;&lt;td valign="top" width="202"&gt;money, decimal, integer, double&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getMaxLength&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取string或者memo字段的最大长度，返回值为数字&lt;/td&gt;&lt;td valign="top" width="202"&gt;string、memo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getMin&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取特定类型字段（money、decimal、integer、double）的最小值，返回值为数字&lt;/td&gt;&lt;td valign="top" width="202"&gt;money, decimal, integer, double&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getName&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的逻辑名称，返回值为字符串&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getOption&lt;/td&gt;&lt;td valign="top" width="769"&gt;输入参数为数字或者字符串，返回一个对应于输入参数的option对象&lt;/td&gt;&lt;td valign="top" width="202"&gt;OptionSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getOptions&lt;/td&gt;&lt;td valign="top" width="769"&gt;返回OptionSet字段的所有下拉选项&lt;/td&gt;&lt;td valign="top" width="202"&gt;OptionSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getParent&lt;/td&gt;&lt;td valign="top" width="769"&gt;返回给定字段的实体记录对象&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getPrecision&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取给定字段的精度值，所谓精度值指的是小数点右边的位数&lt;/td&gt;&lt;td valign="top" width="202"&gt;money, decimal, integer, double&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getRequiredLevel&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的需求级别，返回值包括有：&lt;br /&gt;none：无需求级别；&lt;br /&gt;required：业务必需；&lt;br /&gt;recommanded：建议填写&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getSelectedOption&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取OptionSet字段的当前选定的选项&lt;/td&gt;&lt;td valign="top" width="202"&gt;OptionSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getSubmitMode&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的提交的模式，也就是说，在表单被保存时，特定字段的提交方式，返回值包括有：&lt;br /&gt;always：总是被提交&lt;br /&gt;never：从不被提交&lt;br /&gt;dirty：只有在值发生变化的时候才提交&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getText&lt;/td&gt;&lt;td valign="top" width="769"&gt;返回一个字符串，代表了当前OptionSet字段的选择项的文本信息&lt;/td&gt;&lt;td valign="top" width="202"&gt;OptionSet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getUserPrivilege&lt;/td&gt;&lt;td valign="top" width="769"&gt;返回一个对象，以确定当前用户对本记录的操作权限，该对象的属性包括有：&lt;br /&gt;canRead：是否有读权限&lt;br /&gt;canUpdate：是否有更新权限&lt;br /&gt;canCreate：是否有创建权限&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;getValue&lt;/td&gt;&lt;td valign="top" width="769"&gt;获取字段的值，对于不同类型的字段，值的类型是不同的，包括有：&lt;br /&gt;&lt;table style="width: 593px;" border="1" cellspacing="1" cellpadding="2"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;字段类型&lt;/td&gt;&lt;td valign="top" width="459"&gt;字段值类型&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;bool&lt;/td&gt;&lt;td valign="top" width="459"&gt;布尔型boolean&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;datetime&lt;/td&gt;&lt;td valign="top" width="459"&gt;日期Date&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;decimal&lt;/td&gt;&lt;td valign="top" width="459"&gt;数字Number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;double&lt;/td&gt;&lt;td valign="top" width="459"&gt;数字Number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;integer&lt;/td&gt;&lt;td valign="top" width="459"&gt;数字Number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;money&lt;/td&gt;&lt;td valign="top" width="459"&gt;数字Number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;lookup&lt;/td&gt;&lt;td valign="top" width="459"&gt;数组Array，数组中元素的类型是查找对象lookup object。每个查找对象包含如下的属性：&lt;br /&gt;entityType：查找对象所代表的记录的实体逻辑架构名称&lt;br /&gt;id：查找对象所代表记录的主键值&lt;br /&gt;name：查找对象所代表的记录的主属性的值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;memo&lt;/td&gt;&lt;td valign="top" width="459"&gt;字符串String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;optionset&lt;/td&gt;&lt;td valign="top" width="459"&gt;数字Number，选项的的value属性的值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="133"&gt;string&lt;/td&gt;&lt;td valign="top" width="459"&gt;字符串String&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;removeOnChange&lt;/td&gt;&lt;td valign="top" width="769"&gt;和addOnChange对应，将某个处理函数从相应字段的OnChange事件处理函数列表中移除&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;setRequiredLevel&lt;/td&gt;&lt;td valign="top" width="769"&gt;设置字段的需求级别，接受的输入参数包括有：&lt;br /&gt;none：无需求级别；&lt;br /&gt;required：业务必需；&lt;br /&gt;recommanded：建议填写&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;setSubmitMode&lt;/td&gt;&lt;td valign="top" width="769"&gt;设置提交模式，接受的输入参数包括有：&lt;br /&gt;always：总是被提交&lt;br /&gt;never：从不被提交&lt;br /&gt;dirty：只有在值发生变化的时候才提交&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="129"&gt;setValue&lt;/td&gt;&lt;td valign="top" width="769"&gt;设置字段的值，不同类型的字段接收的值的类型也是不同的，具体的可以参见getValue部分的字段类型与字段值类型的对比介绍&lt;/td&gt;&lt;td valign="top" width="202"&gt;所有&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从Xrm.Page.data.entity.attributes集合中，获取属性的途径有以下几种：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;span style="color: #4b4b4b;"&gt;第一，通过Xrm.Page.data.entity.attributes对象的get方法，获取所有的当前表单中的属性集合，例如：&lt;/span&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; attributeList = Xrm.Page.data.entity.attributes.get(); &lt;/div&gt;&lt;p&gt;&lt;span style="color: #4b4b4b;"&gt;另外，可以将方法指针作为参数传递给get()方法，从而可以根据条件对返回的属性进行筛选，例如下面的代码就是获取表单中所有lookup类型属性的样例代码：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; lookupAttrList = Xrm.Page.data.entity.attributes.get(isLookup);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;function&lt;/span&gt; isLookup(attribute, index)&lt;br /&gt;&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        attribute.getAttributeType == &amp;ldquo;lookup&amp;rdquo;;&lt;br /&gt;&lt;br /&gt;    }&lt;/div&gt;&lt;p&gt;&lt;span style="color: #4b4b4b;"&gt;第二，通过为Xrm.Page.data.entity.attributes.get()方法传入参数，获取参数指定的某个属性，输入参数是某个属性的逻辑名称，例如：&lt;/span&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; firstNameAttr = Xrm.Page.data.entity.attributes.get(&amp;ldquo;firstname&amp;rdquo;);&lt;/div&gt;&lt;p&gt;&lt;span style="color: #4b4b4b;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 就是在客户表单中，获取&amp;ldquo;名&amp;rdquo;这个属性。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #4b4b4b;"&gt;第三，通过简写方式获取某个属性，即通过Xrm.Page.getAttribute()方法，并传入需要获取的属性的逻辑名称，得到某个属性，例如上面第二种途径的简化的写法：&lt;/span&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; firstNameAttr = Xrm.Page.getAttribute(&amp;ldquo;firstName&amp;rdquo;);&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 关于操作属性的方法，有几个是需要注意的：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;首先，操作Lookup类型的属性，由于该类字段的值是一个lookup对象的数组，所以在操作该字段的时候，需要小心。下面是获取lookup类型字段的方法：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; createdByAttr = Xrm.Page.getAttribute(&amp;ldquo;createdby&amp;rdquo;);&lt;br /&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (createdByAttr != &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt;     createdByAttr  = createdByAttr.getValue();&lt;br /&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (createdByAttr != &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt;     {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt;         createdByAttr = createdByAttr[0];&lt;br /&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;lookup对应的关联的主要实体记录的逻辑名称&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; createdBy_entityType = createdByAttr.entityType;&lt;br /&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;一个GUID值，形如xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; createdBy_id = createByAttr.id;&lt;br /&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;lookup字段对应的关联的主要实体记录的主要名称&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; createdBy_name = createdByAttr.name;&lt;br /&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt;     }&lt;br /&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; }&lt;/div&gt;&lt;p&gt;为lookup字段赋值，就是一个反方向的操作：拼装一个lookup对象，将其作为数组的第一个元素，通过setValue()方法将数组赋值给一个lookup字段；&lt;/p&gt;&lt;p&gt;其次，Optionset类型的字段，简单而言，类似于HTML中的select元素。故此，该类型字段，包含有多个下拉选项option，每个选项有一个显示文本text，一个值value。&lt;/p&gt;&lt;p&gt;第三，对于datetime类型的字段，赋值的时候，需要使用Date类型的对象。&lt;/p&gt;&lt;p&gt;第四，表单中被禁用的字段，默认情况下，在保存的时刻，是不会被提交给服务器的，可以使用setSubmitMode()方法，并设置输入参数为&amp;ldquo;dirty&amp;rdquo;，可以将被禁用字段修改后的值提交给服务器。那么如何修改被禁用字段的值呢，当然是使用setValue()方法了。&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2408082.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/20/2408082.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/03/18/2404625.html</id><title type="text">MS CRM 2011的自定义与开发(12)&amp;mdash;&amp;mdash;表单脚本扩展开发(3)</title><summary type="text">继续上文。 Xrm.Page.data.entity，提供了一组函数和集合，分别用于页面所代表实体数据的信息，以及代表该数据所有属性的一个集合，需要注意的是，该集合中只包含界面上显示的字段的信息，...</summary><published>2012-03-18T06:04:00Z</published><updated>2012-03-18T06:04:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/18/2404625.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/18/2404625.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/15/2398369.html" target="_blank"&gt;继续上文&lt;/a&gt;。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.data.entity，提供了一组函数和集合，分别用于页面所代表实体数据的信息，以及代表该数据所有属性的一个集合，需要注意的是，该集合中只包含界面上显示的字段的信息，例如，表单中没有修改者字段，那么属性集合中，不会包含有关修改者字段的信息。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.data.entity对象包含的函数有：&lt;/p&gt; &lt;table border="1" cellspacing="1" cellpadding="2" width="800"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt; &lt;p align="center"&gt;&lt;strong&gt;名称&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="692"&gt; &lt;p align="center"&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;addOnSave&lt;/td&gt; &lt;td valign="top" width="692"&gt;设置表单在保存时需要触发的处理函数，输入参数为方法指针&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;getDataXml&lt;/td&gt; &lt;td valign="top" width="692"&gt;获取表单保存时，发送给服务器的XML字符串信息&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;getEntityName&lt;/td&gt; &lt;td valign="top" width="692"&gt;获取当前表单对应的实例的实体的逻辑名称&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;getId&lt;/td&gt; &lt;td valign="top" width="692"&gt;获取当前表单对应的实例的主键值GUID&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;getIsDirty&lt;/td&gt; &lt;td valign="top" width="692"&gt;用于判断当前表单中的所有字段是否有过更改&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;removeOnSave&lt;/td&gt; &lt;td valign="top" width="692"&gt;和addOnSave函数相逆，将某个处理函数从表单保存操作触发函数列表中移除&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="108"&gt;save&lt;/td&gt; &lt;td valign="top" width="692"&gt;保存操作，有三个输入参数，分别是&lt;br&gt;空：等同于点击Ribbon工具条的“保存”按钮；&lt;br&gt;saveandclose：等同于点击Ribbon工具条的“保存并关闭”按钮；&lt;br&gt;saveandnew：等同于点击Ribbon工具条的“保存并新建”按钮；&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面以addOnSave方法为例，说明如何向Microsoft Dynamics CRM 2011的表单中添加处理函数。&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;1. 打开相应的实体的表单编辑器；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;2. 点击Ribbon工具条中的窗体属性按钮，系统弹出“窗体属性”对话框；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;3. 点击窗体属性对话框的“事件列表”工具条上的“添加”按钮，该操作代表了要向现有表单添加脚本库文件，此时，系统弹出“查找记录”对话框；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;4. 在“查找记录”对话框中，将会列出所有的可用的类型为Javascript的web资源，如果这些Javascript资源不能够满足要求，那么需要点击对话框左下方的“新建”按钮，通过新建Javascript资源的方式，添加新的脚本文件；&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#4b4b4b"&gt;以上操作&lt;/font&gt;，如下图所示，红色箭头代表了先后的操作顺序。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181401494160.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402277599.png" width="904" height="516"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 点击“新建”按钮后，系统弹出了“新建web资源”界面，如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402336591.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402386313.png" width="904" height="509"&gt;&lt;/a&gt; &lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;在“名称”文本框中，输入新建的web资源的唯一名称，本例中，使用了new_addSaveScript.js作为唯一名称，其中“new_”是前缀名称；&lt;/p&gt; &lt;p&gt;在“显示名称”文本框中，输入一个易于记忆的显示名称，本例中，使用了“addSave function sample”作为显示名称；&lt;/p&gt; &lt;p&gt;在“说明”文本框中，输入对当前web资源的描述性信息，包括资源的用途、版本等等信息都是可以的；&lt;/p&gt; &lt;p&gt;在“类型”下拉框部分，系统提供了所有支持的web资源类型，如下图所示；&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402396761.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402446874.png" width="379" height="160"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果类型选择为“网页”、“脚本”、“样式表”、“数据”，那么将在“类型”下拉框的右侧出现一个“文本编辑器”按钮，效果如下图所示&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402442829.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402458468.png" width="610" height="49"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;对于PNG、JPG、GIF、ICO以及XAP格式的资源，那么需要点击“上载文件”文本框旁边的“浏览”按钮，以便将本机上存储的相应格式的文件上传到服务器中，对于其他格式的web资源，可以使用MS CRM系统的文本编辑器进行输入，也可以使用上传文件的方式将相应的资源文件上传到服务器中。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 本例中，使用MS CRM 2011提供的文本编辑器输入脚本函数。输入的脚本内容如下图所示：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402492452.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402527176.png" width="762" height="373"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 共书写了两个脚本函数，内容如下：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;function addOnSave_OnLoad()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.data.entity.addOnSave(myFirstAddOnSaveSample);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.data.entity.addOnSave(mySecondAddOnSaveSample);&lt;br&gt;}  &lt;p&gt;function myFirstAddOnSaveSample()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; alert("First handler function");&lt;br&gt;}  &lt;p&gt;function mySecondAddOnSaveSample()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; alert("Second hander function");&lt;br&gt;} &lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 编写完脚本资源，点击“确定”按钮，返回“新建web资源”界面，点击Ribbon工具条中的“保存并关闭”按钮，返回“查找记录”对话框，选择新建的web资源，点击“确定”按钮，返回“窗体属性”对话框，最终的“窗体属性”对话框的效果如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181402563527.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403009529.png" width="647" height="724"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 至此，脚本库的添加工作已经完成，下面就是将表单中的事件与脚本库中的脚本函数进行挂接的工作。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在“事件处理程序”部分，根据我们需要添加事件处理函数的具体情况，&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;首先，确定“控件”下拉框的控件名称，本例是希望在窗体被加载的时候，调用addOnSave方法，以期在窗体保存操作时，可以调用上面书写的处理函数，所以，控件选择为“窗体”；&lt;/p&gt; &lt;p&gt;其次，选择事件，本例中，选择OnLoad事件；&lt;/p&gt; &lt;p&gt;第三，点击“添加”按钮，指定事件处理函数，系统会弹出“处理程序属性”对话框，在“函数”文本框中，输入处理程序的名称，本例中，输入“addOnSave_OnLoad”；&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403106899.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403127196.png" width="632" height="501"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最终的处理程序列表如下图所示：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403173231.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403239366.png" width="586" height="288"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 点击“确定”按钮，返回表单编辑器主界面，点击Ribbon工具条中的“保存”按钮。在保存完成后，点击“发布”按钮，完成功能修改后的生效工作。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 发布完成后，返回表单页面，我们测试一下。点击“保存”按钮，系统会依次弹出“First Handler function”以及“Second Handler function”两个对话框，如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181403337424.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203181404015935.png" width="904" height="516"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 以上，展示了几类内容：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;向表单中添加脚本函数处理程序的步骤；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;添加web资源的方法；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;简单的Xrm.Page.data.entity方法的调用样例；&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2404625.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/18/2404625.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/03/15/2398369.html</id><title type="text">MS CRM 2011的自定义与开发（12）&amp;mdash;&amp;mdash;表单脚本扩展开发（2）</title><summary type="text">之前忙于出差，累得稀里哗啦的，也没有时间更新了。现在，可以继续写文章了。言归正传。 上一篇，介绍了Microsoft Dynamics CRM中，表单开发方面的基本概念和知识，本文将继续表单脚本开...</summary><published>2012-03-15T09:09:00Z</published><updated>2012-03-15T09:09:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/15/2398369.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/03/15/2398369.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 之前忙于出差，累得稀里哗啦的，也没有时间更新了。现在，可以继续写文章了。言归正传。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/27/2369846.html" target="_blank"&gt;上一篇&lt;/a&gt;，介绍了Microsoft Dynamics CRM中，表单开发方面的基本概念和知识，本文将继续表单脚本开发的介绍。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不同于以往的几个版本，MS CRM 2011中，将表单中的内容分为两大类，分别是界面UI管理器以及数据管理器，分别是：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;UI管理器：用于操纵表单中的各个HTML元素；&lt;/p&gt; &lt;p&gt;数据管理器：用于操纵表单所展现的实体实例的数据。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不管是哪一种管理器，都需要和Xrm.Page对象打交道。Xrm.Page对象提供了与MS CRM 2011的表单进行交互的一系列的对象和函数。&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;注意：在MS CRM 3以及MS CRM 4版本中的crmForm对象已经被弃用了，如果需要从MS CRM 4升级到MS CRM 2011，那么在表单脚本中，需要将有关crmForm的脚本内容，更新为MS CRM 2011的Xrm.Page的脚本。国外的同行开发了一个javascript converter的工具，用于将MS CRM 4中的有关crmForm内容自动转换为Xrm.Page的脚本。&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page是一个命名空间对象，其下包含了三大类的对象层次体系，形成的层次结构树如下图所示：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203151708227432.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201203/201203151708316060.png" width="670" height="450"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 由上图可见，Xrm.Page命名空间中，包含有三大部分的内容，分别是：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;Xrm.Page.context：Xrm.Page.context对象提供了对上下文信息的访问，包括获取特定的组织信息、特定的用户信息以及通过查询字符串QueryString传递给表单的参数；&lt;/p&gt; &lt;p&gt;Xrm.Page.data.entity：表单的数据管理器，该对象提供了对表单所代表的实体数据的访问、管理与控制；&lt;/p&gt; &lt;p&gt;Xrm.Page.ui：表单的界面UI管理器，该对象提供了对表单中各类界面元素的管理与控制；&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Xrm.Page.context提供了如下的一些函数：&lt;/p&gt; &lt;table border="1" cellspacing="1" cellpadding="2" width="800"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt; &lt;p align="center"&gt;&lt;strong&gt;名称&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="622"&gt; &lt;p align="center"&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getAuthenticationHeader&lt;/td&gt; &lt;td valign="top" width="622"&gt;已经弃用了，该函数用于在Javascript访问MS CRM Webservice时，生成访问所需的SOAP头信息&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getCurrentTheme&lt;/td&gt; &lt;td valign="top" width="622"&gt;在Outlook客户端使用中，获取用户选择的主题（Theme）&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getOrgLcid&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取当前组织的基础语言代码，例如简体中文版，那么就是2052，如果是英文版，那么值就是1033&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getOrgUniqueName&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取当前组织的唯一名称&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getQueryStringParameters&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取传送给页面的查询字符串参数,以键值对的方式存放于一个数组中&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getServerUrl&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取服务器的URL地址，如果是在Outlook客户端在离线环境下使用本函数，将返回本地的一个地址&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getUserId&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取当前用户的主键值，一个GUID值&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getUserLcid&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取当前用户选定的主语言的ID值&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;getUserRoles&lt;/td&gt; &lt;td valign="top" width="622"&gt;获取用户的角色&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;isOutlookClient&lt;/td&gt; &lt;td valign="top" width="622"&gt;判断，当前的上下文环境，是否处于Outlook客户端环境下&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;isOutlookOnline&lt;/td&gt; &lt;td valign="top" width="622"&gt;判断，当前的上下文环境，是否处于Outlook离线客户端环境下；&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="178"&gt;prependOrgName&lt;/td&gt; &lt;td valign="top" width="622"&gt;为特定路径预置组织名称&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于表单环境下，直接使用Xrm.Page.context即可访问上下文环境。如果是在表单外的环境中，例如HTML形式的web资源，那么就需要通过添加ClientGlobalContext.js.aspx文件的方式，完成对GetGlobalContext函数的引用，才可以访问Xrm.Page.context对象，从而访问上面列表中的方法以获取上下文环境。ClientGlobalContext.js.aspx文件的位置是/Webresources文件夹下，所以，在web资源中添加对ClientGlobalContext.js.aspx文件的引用时，需要注意路径问题。举例来说，有一个HTML资源，其名称为new_/myhtmlpage/html1.htm，那么如果需要在head元素下添加script子元素时，script子元素的src属性的设置就需要注意啦，正确的书写方式应该是&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;……&lt;/p&gt; &lt;p&gt;&amp;lt;head&amp;gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ……&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;script type=”text/javascript” src=”&lt;strong&gt;&lt;font color="#ff0000" size="5"&gt;../../&lt;/font&gt;&lt;/strong&gt;ClientGlobalContext.js.aspx” /&amp;gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ……&lt;/p&gt; &lt;p&gt;&amp;lt;/head&amp;gt;&lt;/p&gt; &lt;p&gt;……&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 通过”../../”的方式，使用相对路径，已经指定了文件夹到了”webresources”目录下，同时，ClientGlobalContext.js.aspx文件就在WebResources目录下，从而完成了在HTML web资源中对ClientGlobalContext.js.aspx文件的引用。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2398369.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/03/15/2398369.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/27/2369846.html</id><title type="text">MS CRM 2011的自定义与开发（12）&amp;mdash;&amp;mdash;表单脚本扩展开发（1）</title><summary type="text">上面的文章中，介绍了如何编写插件以扩展业务逻辑，插件是运行于应用服务器上的由C#或者VB.NET编写的Assembly。除了插件之外，还可以借助Microsoft Dynamics CRM 2011...</summary><published>2012-02-27T06:52:00Z</published><updated>2012-02-27T06:52:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/27/2369846.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/27/2369846.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上面的文章中，介绍了如何编写插件以扩展业务逻辑，插件是运行于应用服务器上的由C#或者VB.NET编写的Assembly。除了插件之外，还可以借助Microsoft Dynamics CRM 2011平台提供的web资源以及表单编辑器，设定表单页面中的业务逻辑，也就是表单脚本扩展，以下的几篇文章都将是围绕着这一主题进行展开。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 表单脚本扩展应用的主要目的是即时响应用户在浏览器中做出的操作，提供良好的客户体验。主要的应用包括以下几类：&lt;/p&gt; &lt;li&gt;客户端输入数据的验证、格式的调整；  &lt;li&gt; &lt;p&gt;响应用户动作，操纵控制界面HTML的外观、行为、数据等；&lt;/p&gt; &lt;li&gt; &lt;p&gt;响应用户动作，从后端平台或者其他的系统，使用Ajax获取数据；&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 表单脚本扩展开发主要使用的技术就是Javascript脚本的开发，通过开发脚本函数，作为MS CRM表单级别的几个扩展点，即表单事件，的事件处理函数，以完成表单级别的扩展。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MS CRM表单主要包含有5个事件，分别是：&lt;/p&gt;&lt;/li&gt; &lt;ol&gt; &lt;li&gt;OnLoad事件：加载窗体后，会触发 OnLoad 事件。无法在OnLoad事件中阻止加载窗口。使用 OnLoad 事件可以准备要在窗体中使用的数据。可以使用 OnLoad 事件执行的操作包括：  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;根据变化的值执行计算。 &lt;/p&gt; &lt;p&gt;提醒用户。 &lt;br&gt;禁用不应更新的字段。&lt;/p&gt;&lt;/blockquote&gt; &lt;li&gt; &lt;p&gt;OnSave事件：当用户按下“保存”或“保存并关闭”按钮，或者触发会导致保存窗体的其他操作（如，使用 Save 方法）后，会触发该事件。该事件始终会发生，即使窗体中的数据没有变化。可以取消 OnSave 事件以阻止保存数据。正是由于这个原因，经常使用 OnSave 事件验证数据。&lt;strong&gt;&lt;em&gt;需要注意，OnSave 事件并不对应于标准 HTML OnSubmit 事件&lt;/em&gt;&lt;/strong&gt;。&lt;/p&gt; &lt;li&gt; &lt;p&gt;OnChange事件：可在所有字段中使用 OnChange 事件。OnChange 事件要求具备两个条件： &lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;字段中的数据必须发生了更改。  &lt;p&gt;字段必须失去焦点。 &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;该事件发生后，将重新验证字段中的数据。这意味着无法使用该事件输入有效数据。  &lt;p&gt;可以使用 OnChange 事件执行的操作包括：  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;根据变化的值执行计算以更改其他字段。  &lt;p&gt;更改字段的格式，例如，电话号码。  &lt;p&gt;实现动态选择列表（下拉列表）。 &lt;/p&gt;&lt;/blockquote&gt; &lt;li&gt; &lt;p&gt;TabStateChange事件：当选项卡展开或折叠时会发生此事件。您可能要推迟代码的执行直至选项卡展开。 此事件在使用脚本修改 IFRAME 控件的 src 属性时非常重要。IFRAME 将在选项卡展开时刷新。将删除对 src 属性的任何更改。如果与 IFRAME 的 src 属性交互，则应该始终在 TabStateChange 事件中包含此代码，而不是 Onload 事件中。 &lt;/p&gt; &lt;li&gt; &lt;p&gt;OnReadyStateComplete事件：除非 IFRAME 的内容已完全加载，否则与 IFRAME 内容交互的任何脚本都会失败。一旦 IFRAME 内容完成加载，此事件便会提供可包含要执行脚本的位置。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2369846.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/27/2369846.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/14/2351126.html</id><title type="text">MS CRM 2011 Q2的一些更新</title><summary type="text">最近，Microsoft Dynamics CRM产品组发布了一个路线图，标明了在Q2发布的一个Update中包含的内容。主要包括：移动客户端、跨浏览器、与社交网络的集成、行业解决方案模板、SQL ...</summary><published>2012-02-14T07:09:00Z</published><updated>2012-02-14T07:09:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/14/2351126.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/14/2351126.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最近，Microsoft Dynamics CRM产品组发布了一个路线图，标明了在Q2发布的一个Update中包含的内容。主要包括：移动客户端、跨浏览器、与社交网络的集成、行业解决方案模板、SQL Server 2012方面的支持以及认证考试方面的信息，下面逐点介绍：&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1. Microsoft Dynamics CRM Mobile&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 自微软CRM 3.0时代开始，产品组就发布过有关移动客户端的产品，包括瘦客户端，包括使用WAP方式访问CRM站点，以及专用于手机客户端的产品。其他第三方的厂商也提供了各自的移动客户端产品。对于常见的移动平台，例如IPhone、Windows Phone、Android以及BlackBerry和Symbian等，都有厂商提供了移动客户端产品。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 目前，微软官方准备推出移动客户端产品。其支持的平台如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508254231.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508273033.png" width="604" height="306"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下图是IPad2上面的截屏效果&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508312906.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508386075.png" width="604" height="454"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Dynamics CRM移动客户端使用集中管理，管理员配置完成表单、数据类型、视图以及离线同步规则和导航项目，这些配置信息一经发布，无论终端用户使用哪一种移动设备都是可以使用。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 目前有两种部署模式，一种是CRM Online版本，由微软负责服务器的管理、运维，如果不能够满足要求，那么可以在组织内部部署该移动解决方案。当然了，这两种都是要付费的。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. 跨浏览器&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在2012 Q2的更新中，将会允许目前市场上流行的各种浏览器访问微软CRM。说句心理话，这是由来已久的需求了，以往经常听到客户抱怨，为什么只能够使用IE访问Dynamics CRM呢？这也太封闭了吧，国际大厂商啊，做的这么封闭。好了，这次更新终于完成了这个进步。下图是对浏览器的支持情况&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508475953.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/20120214150849611.png" width="604" height="164"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看出，Q2更新中，对市面上流行浏览器已经做到了一定的支持。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. Rapid View Form快速视图表单&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在很多业务场景中，用户只需要查看信息，而不是进行编辑，或者是要在审查数据的基础上再确定是否要编辑。例如，呼叫中心人员，在客户来电时候，是先弹屏，显式来电的客户信息，而后根据与客户的沟通而确定采取哪一类操作，那么出于客户体验以及呼叫中心人员的操作体验，都需要快速显式客户信息。基于此基础之上，产品组推出了Rapid View Form，我给出的翻译是快速视图表单，提供一个只读的、可以快速打开的实体表单。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4. Enhanced Social 社交网络加强版&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MS CRM通过Activity Seeds，提供了与微博以及其他社交网络与MS CRM之间的集成。Activity Seeds解决方案现在就可以从微软CRM的Marketing Place中下载。这个解决方案，主要提供了与Facebook以及Twitter的集成。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5. 行业解决方案模板&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不得不说，产品组已经开始意识到需要行业解决方案的重要性，并且将其提到了议事日程，而且付诸实施。此次提供的行业解决方案中都包括了数据模型、预制数据、仪表板、工作流以及样例数据。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Q2更新会发布的行业解决方案包括：Life Annuity Insurance Sales（年金保险销售）、Non-Profit（非营利组织）、Health Plan Sales(健康计划销售）以及Wealth Management（财富管理）。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面是各个解决方案的介绍&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141508547792.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141509022554.png" width="804" height="427"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 限于个人能力所限，无法进行准确分析，各位同学只能够自己翻译一下了。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面是年金保险销售解决方案的截屏。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/20120214150908150.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202141509117415.png" width="604" height="284"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6. 支持SQL Server 2012&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SQL Server 2012要发布了，微软CRM产品组也为此做出了相应的工作，从而可以允许CRM允许于SQL Server 2012，从而利用SQL Server 2012的新特性。包括有：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;性能提升；&lt;/p&gt; &lt;p&gt;下一代的BI，主要是Power View方面；&lt;/p&gt; &lt;p&gt;为CRM预置的Power Pivot模型；&lt;/p&gt; &lt;p&gt;预定义的Power View报表；&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2351126.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/14/2351126.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/08/2343294.html</id><title type="text">MS CRM 2011的自定义和开发（11）&amp;mdash;&amp;mdash;插件(plugin)开发（四）</title><summary type="text">上面几篇文章介绍了Microsoft Dynamics CRM 2011中如何进行插件开发，本文将介绍插件的调试。 调试的基本步骤是 1. 注册、部署插件，这部分内容在上一篇Blog中已经介绍，...</summary><published>2012-02-08T14:21:00Z</published><updated>2012-02-08T14:21:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/08/2343294.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/08/2343294.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上面几篇文章介绍了Microsoft Dynamics CRM 2011中如何进行插件开发，本文将介绍插件的调试。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 调试的基本步骤是&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;1. 注册、部署插件，这部分内容在上一篇Blog中已经介绍，不再赘述；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#4b4b4b"&gt;2. 将插件的pdb文件拷贝到CRM安装目录下的“Server\Bin\Assembly”文件夹下，一般而言，如果使用默认配置安装的CRM系统，那么此文件夹的全路径是“C:\Program Files\Microsoft Dynamics CRM Server\Server\bin\assembly”；&lt;/font&gt;&lt;/p&gt; &lt;p&gt;3. 配置调试器，即通过Visual Studio .net的附加到相应进程进行调试：&lt;/p&gt; &lt;p&gt; &lt;li&gt;对于运行于服务器上的插件，需要附加的进程是w3wp.exe进程；  &lt;li&gt;如果是调试脱机客户端中的插件，附加的进程是Microsoft.Crm.Application.Hoster.exe；  &lt;li&gt;如果是异步方式运行的插件，那么附加的进程是CrmAsyncService.exe  &lt;li&gt;如果是运行在沙盒Sandbox中的插件，那么附加的进程是Microsoft.Crm.Sandbox.WorkerProcess.exe  &lt;p&gt;4. 在插件类中，设置断点；&lt;/p&gt; &lt;p&gt;5. 开始调试，进行界面操作，以触发插件的运行，以便可以在IDE中开始插件的调试工作。&lt;/p&gt;&lt;/li&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 以下是各个步骤的截屏&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1. 插件注册，请参看文章《&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html"&gt;MS CRM 2011的自定义和开发（11）——插件(plugin)开发（三）&lt;/a&gt;》；&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. 拷贝pdb文件。首先打开插件项目的文件夹，导航到bin\debug目录下，找到插件程序集相关的pdb文件。如下图的红色方框区域所示&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219199640.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="SNAGHTML350fa8a4" border="0" alt="SNAGHTML350fa8a4" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/20120208221934734.png" width="802" height="479"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 将该文件拷贝到CRM$\Server\Bin\Assembly目录下。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. 配置调试器，本例中，使用Visual Studio .Net 2010进行调试。点击“调试”—&amp;gt; “附加到进程”，系统弹出“附加到进程”对话框，在其中列出了当前服务器上运行的进程，根据待调试插件的运行模式、部署模式，选择目标进程，而后点击“附加”按钮即可。如果在进程列表中没有目标进程，那么，点击“显示所有会话中的进程”复选框。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219396213.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219461923.png" width="904" height="469"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在附加w3wp.exe进程时，如果服务器的IIS中有多个站点同时处于活动状态，进程列表中就会出现多个w3wp.exe进程，这些进程之间的区别只是第二列ID列的信息不同，那么哪个进程是我们需要附加的进程呢？对于这种情况，可以通过IIS管理器来获得需要附加的进程。运行IIS管理器，在左侧导航栏中，点击第二个节点，而后再在右侧的内容区域点击“工作进程”，如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219506256.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219554899.png" width="904" height="522"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 内容区域会切换到工作进程列表界面，其中显示了当前IIS中所有处于运行状态的W3wp进程，其中第一列是w3wp.exe进程所对应的应用程序池名称，第二列信息就是进程ID。效果如下图所示，其中，蓝色区域圈定的就是进程ID信息，这将会有助于我们在“附加到进程”对话框中选择正确的进程予以附加：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082219595851.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="SNAGHTML352220a1" border="0" alt="SNAGHTML352220a1" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220073928.png" width="904" height="520"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4. 设置断点，这没有啥可以说的了，对于经常使用Visual Studio.Net的各位同学们已经是驾轻就熟；&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5. 运行应用程序，或者使用界面操作的方式，或者使用C#开发的测试程序，总而言之，就是调用组织服务，发起某个请求，以触发插件的运行。本例中的插件是注册于account的pre-create事件上。所以呢，就是在crm中新建客户记录的时候会触发插件的运行。ok，通过浏览器操作，新建一条客户记录。记录内容如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220113485.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220151472.png" width="904" height="514"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 点击保存按钮，会向MS CRM的组织服务发送创建请求，从而触发插件的运行，此时，由于VS附件到进程已经开启，将可以对插件进行调试了。效果如下图所示：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220191345.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220263118.png" width="904" height="559"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果Visual Studio没有被触发，或者插件类的断点没有起作用。首先，要看一下当前MS CRM是否允许进行debug，若否，可打开debug开关。打开Debug开关的步骤如下：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;打开CRM$\CrmWeb目录，其中CRM$指的是微软CRM的安装目录，本例中是“C：\Program files\Microsoft Dynamcis CRM Server”；&lt;/p&gt; &lt;p&gt;找到web.config文件，使用任意编辑器打开该文件；&lt;/p&gt; &lt;p&gt;在web.config文件中找到，&amp;lt;compiliation defaultLanguage=”C#” debug=”…&amp;gt;这一句。默认情况下，debug开关的值是false，为了能够调试，需要将其设置为true，设置完成后，重新启动IIS；&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 设置debug开关项的示意图如下所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220303024.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202082220384788.png" width="904" height="559"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 此外，除了使用调试器进行debug之外，还可以借助日志与跟踪服务，来确定插件的执行顺序，这样可以方便我们在不启用VS等调试工具的前提下，确定问题的根源所在。跟踪服务ITracingService，也是插件执行上下文中的一个组成部分，可以通过IServiceProvider.GetService()方法获得，样例代码例如：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ITracingService实例化时候，可以利用trace方法，创建跟踪日志信息，例如&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;tracingService.Trace(“Plug-in execution begin”);&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2343294.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/08/2343294.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html</id><title type="text">MS CRM 2011的自定义和开发（11）——插件(plugin)开发（三）</title><summary type="text">插件开发完成后，就需要注册、调试、部署了。 在注册之前，需要着重指出的是，必须对插件程序集进行签名，具体步骤是，在Visual Studio中，右键点击项目名称，快捷菜单中选择“属性”，在项目属性...</summary><published>2012-02-06T14:54:00Z</published><updated>2012-02-06T14:54:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 插件开发完成后，就需要注册、调试、部署了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在注册之前，需要着重指出的是，必须对插件程序集进行签名，具体步骤是，在Visual Studio中，右键点击项目名称，快捷菜单中选择&amp;ldquo;属性&amp;rdquo;，在项目属性对话框中，点击&amp;ldquo;签名&amp;rdquo;页签， 勾选&amp;ldquo;为程序集签名&amp;rdquo;，在&amp;ldquo;选择强名称密钥文件&amp;rdquo;下拉框中，选择&amp;ldquo;新建&amp;rdquo;创建一个新的密钥文件或者&amp;ldquo;浏览&amp;rdquo;选择一个已有的密钥文件。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062252444877.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062252473571.png" alt="image" width="826" height="470" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 注册使用插件注册工具PluginRegistrationTool了，该工具位于SDK\Tools\PluginRegistration目录下，需要使用Visual Studio .Net 2010编译一下pluginregistrationtool项目。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 使用插件注册工具进行插件注册的步骤非常简单，&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1. 运行插件注册工具，如果是初次运行，在Connections控制板中没有任何内容，需要点击工具条的&amp;ldquo;Create New Connection&amp;rdquo;按钮，而后在&amp;ldquo;Connection Information&amp;rdquo;区域的Label文本框中输入代表连接的注记名称，在&amp;ldquo;Discovery Url&amp;rdquo;文本框中输入服务器的地址（包括端口号），在&amp;ldquo;User Name&amp;rdquo;文本框中输入包括域名在内的用户名称。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062252507522.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062252546805.png" alt="image" width="826" height="535" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. 点击&amp;ldquo;Connect&amp;rdquo;按钮，而后再在弹出的Windows登陆窗口中输入密码，注册工具会去获取目标部署中的所有组织。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062252575740.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253015056.png" alt="image" width="833" height="539" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. 选择需要连接的组织，而后点击&amp;ldquo;Connect&amp;rdquo;按钮。注册工具获取目标组织的消息、用户、已经注册的插件、步骤、映像等等所有信息，而后，将在右侧的区域显示出目标组织中的所有已经注册插件程序集。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253057994.png"&gt;&lt;img style="display: inline; border: 0px;" title="SNAGHTML2af29924" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253092883.png" alt="SNAGHTML2af29924" width="833" height="539" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 右侧的区域主要分为四个部分，最上方的工具条、左上方的已注册插件以及自定义工作流活动程序集列表，右上方的PropertyGrid显示了列表中当前选择项目的属性，下方的区域是列表中当前选择项的一些内容。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果需要注册插件。点击工具条中的&amp;ldquo;Register&amp;rdquo;按钮，系统会弹出下拉菜单，如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253104619.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253117542.png" alt="image" width="290" height="96" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 选择&amp;ldquo;Register New Assembly&amp;rdquo;，就开始了注册插件程序集。点击该菜单项之后，系统弹出&amp;ldquo;Register New Plugin&amp;rdquo;窗口，点击&amp;ldquo;Step #1：Specify the location of the Assembly&amp;nbsp; to Analyze&amp;rdquo;文本框旁的按钮&amp;ldquo;&amp;hellip;&amp;rdquo;，系统将弹出对话框，以便找到程序集。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253159574.png"&gt;&lt;img style="display: inline; border: 0px;" title="SNAGHTML2b0e8ec9" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253198956.png" alt="SNAGHTML2b0e8ec9" width="825" height="544" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 选定程序集后，点击&amp;ldquo;打开&amp;rdquo;按钮，返回&amp;ldquo;Register New Plugin&amp;rdquo;窗口。会在&amp;ldquo;Step #2&amp;rdquo;的列表框中列出程序集中所有的插件类。如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253234860.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253279193.png" alt="image" width="499" height="551" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在&amp;ldquo;Step #3&amp;rdquo;中，可以选择隔离模式Isolation Mode，有两种模式：None以及沙盒Sandbox，如果是将插件放置在沙盒中，那么插件类将无法访问服务器上的文件系统、应用程序日志以及注册表等信息，而注册为None模式则没有这个限制。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在&amp;ldquo;Step #4&amp;rdquo;中，设定程序集存放位置：数据库Database、文件系统Disk以及全局缓存GAC中，如果正式生产环境部署，那么推荐部署在数据库中，如果是开发环境，推荐部署在Disk上，以方便调试。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 点击&amp;ldquo;Register Selected&amp;rdquo;按钮，完成插件程序集的注册工作。返回主界面，对比之前的程序集列表，可以看出，新增的插件的相关内容已赫然在目。如下图红色方框区域所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253303700.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253341032.png" alt="image" width="497" height="398" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面开始完成对事件的订阅工作。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 选择需要订阅事件的插件类 &amp;ndash;〉 点击&amp;ldquo;Register&amp;rdquo; &amp;ndash;〉 &amp;ldquo;Register New Step&amp;rdquo;，系统弹出&amp;ldquo;Register New Step&amp;rdquo;窗口。由于是以前一篇文章中的AccountNumberPlugin举例，所以，需要订阅的消息是客户Accont实体的Create消息的前置事件，所以，在&amp;ldquo;Register New Step&amp;rdquo;窗口，做出如下的设置：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 消息Message文本框内容：Create；&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 主要实体Primary Entity文本框内容：account；&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 阶段Eventing pipeline Stage of Execution: Pre-Operation（CRM 2011 Only）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 模式Execution Mode：Synchronous&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 部署Deployment：Server&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最终效果如下图所示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253389019.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253435893.png" alt="image" width="816" height="393" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 点击&amp;ldquo;Register New&amp;rdquo;按钮，完成步骤注册，返回注册工具主界面。可以看出在插件列表中又多出一行新内容，对应了刚刚注册的Step，效果如下图的红色方框区域所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253462320.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253519293.png" alt="image" width="825" height="661" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果某个插件类中使用了映像Image，那么需要针对相应步骤设定Image信息，点击&amp;ldquo;Register&amp;rdquo; &amp;ndash;〉 &amp;ldquo;Register New Image&amp;rdquo;，系统弹出&amp;ldquo;Register New Image&amp;rdquo;窗口，在&amp;ldquo;Step列表&amp;rdquo;中选择需要添加Image的步骤，而后设定前期映像、后期映像的信息。效果如下图所示。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253555785.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202062253563442.png" alt="image" width="570" height="503" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 经过以上的几个步骤，即完成了插件程序集的注册、步骤的注册以及映像Image的注册。下面即开始进行测试，看看是否能够满足业务要求，如果出现了错误需要进行调试等等内容，在后续章节中再进行介绍。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2340661.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2339490.html</id><title type="text">MS CRM 2011的自定义和开发（11）——插件(plugin)开发（二）</title><summary type="text">上一篇文章《MS CRM 2011的自定义和开发（11）——插件(plugin)开发（一）》，介绍了Microsoft Dynamics CRM 2011中插件plugin的基本概念，事件处理子系统...</summary><published>2012-02-05T18:36:00Z</published><updated>2012-02-05T18:36:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2339490.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2339490.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上一篇文章《&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/02/2336147.html"&gt;MS CRM 2011的自定义和开发（11）&amp;mdash;&amp;mdash;插件(plugin)开发（一）&lt;/a&gt;》，介绍了Microsoft Dynamics CRM 2011中插件plugin的基本概念，事件处理子系统的概念，本篇文章将介绍插件的开发的方法。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以使用与.Net Framework 4.0 CLR兼容的任何开发语言编写插件代码，笔者我只会C#，所以后续代码都是C#代码，如果是VB.Net或者精通其他语言的程序员同学，我就爱莫能助啦。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 为了编写插件，需要在插件的Project中添加Microsoft.Xrm.SDK.dll以及Microsoft.Crm.Sdk.Proxy.dll两个程序集的引用。这两个程序集可以在SDK\bin目录下面找到。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 插件都是Microsoft.Xrm.Sdk.IPlugin接口的实现类，所有的插件类都必须实现IPlugin接口。IPlugin接口只有一个Execute方法。该接口的代码如下所示：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;interface&lt;/span&gt; IPlugin&lt;br /&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; {&lt;br /&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; Execute(IServiceProvider serviceProvider);&lt;br /&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; }&lt;/div&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从上面代码可以看出Execute方法只有一个输入参数serviceProvider，该参数的类型是IServiceProvider，是事件执行管道传递给当前插件的所有消息的容器，存储了在插件中可能要使用到的各类对象。通过IServiceProvider接口的GetService方法，可以获取执行上下文IPluginExecutionContext、组织服务工厂IOrganizationServiceFactory以及跟踪服务ITracingService等实例。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一个插件的样例代码如下所示：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;class&lt;/span&gt; SamplePlugin: IPlugin&lt;br /&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; Execute(IServiceProvider serviceProvider)&lt;br /&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt;     {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 获取插件执行上下文&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt;         IPluginExecutionContext context = &lt;br /&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt;             (IPluginExecutionContext)serviceProvider.GetService(&lt;span style="color: #0000ff;"&gt;typeof&lt;/span&gt;(IPluginExecutionContext));&lt;br /&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 获取组织服务工厂实例&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt;         IOrganizationServiceFactory factory = &lt;br /&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt;             (IOrganizationServiceFactory)serviceProvider.GetService(&lt;span style="color: #0000ff;"&gt;typeof&lt;/span&gt;(IOrganizationServiceFactory));&lt;br /&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;获取组织服务实例&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt;         IOrganizationService service = factory.CreateOrganizationService(context.UserId);&lt;br /&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;获取跟踪服务&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt;         ITracingService tracingService = (ITracingService)serviceProvider.GetService(&lt;span style="color: #0000ff;"&gt;typeof&lt;/span&gt;(ITracingService));&lt;br /&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt;         {&lt;br /&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt;             &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 插件业务逻辑代码&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt;         }&lt;br /&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;catch&lt;/span&gt; (FaultException&amp;lt;OrganizationServiceFault&amp;gt; ex)&lt;br /&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt;         {&lt;br /&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt;             &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;异常处理代码&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt;         }&lt;br /&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt;     }&lt;br /&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; }&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 插件执行上下文IPluginExecutionContext中，包括有事件处理管道传递给插件的各类信息，包括执行插件的运行时环境、执行管道相关信息以及触发Web服务的实体实例信息。IPluginExecutionContext接口中的成员列表如下所示：&lt;/p&gt;&lt;table style="width: 784px;" border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;&lt;strong&gt;名称&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;td width="687"&gt;&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;ParentContext&lt;/p&gt;&lt;/td&gt;&lt;td valign="top" width="687"&gt;&lt;p&gt;从父管道操作中获取执行上下文信息。父子管道产生原因在于CRM系统中某些消息请求可能会产生其他消息请求。举例来说AssignRequest请求会产生一个UpdateRequest请求，如果两个插件A和U分别订阅了AssignRequest消息和UpdateRequest消息，那么在AssignRequest产生时，插件A、插件U将依次执行，此时插件U的执行上下文的ParentContext属性将被赋予插件A的执行上下文。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;Stage&lt;/p&gt;&lt;/td&gt;&lt;td valign="top" width="687"&gt;&lt;p&gt;获取同步执行模式插件在执行管道中所处的阶段&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IPluginExecutionContext接口继承自IExecutionContext接口，在IExecutionContext接口中，包含了大量的有关上下文的信息，如下表所示：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;&lt;strong&gt;名称&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;BusinessUnitId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取执行管道所处理的实体实例的业务部门GUID。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;CorrelationId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;该属性的用途CRM平台为了避免出现无限死循环&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Depth&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取当前插件在调用堆栈中的深度。也是为了避免出现无限死循环。插件开发人员可以在插件代码中对该属性进行判断从而避免出现无限死循环。经常的一种使用情景是，订阅了UpateRequest的插件代码中还执行了Update操作。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;InitiatingUserId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取当前执行事件管道的系统用户的GUID.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;InputParameters&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取触发插件执行的请求消息参数.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;IsExecutingOffline&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取当前插件是否运行在脱机环境中&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;IsInTransaction&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取插件是否执行在数据库事务中。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;IsOfflinePlayback&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;如果插件可以运行在脱机环境中，那么在客户端与CRM服务器同步时，很可能由于数据同步造成服务器端同一插件再次执行一遍，从而导致数据出现了错误，此时，就需要在插件中使用本数据判断，是否是由于离线客户端与CRM服务器同步触发了本插件的运行。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;IsolationMode&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;判断插件是否执行在沙盒Sandbox中。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;MessageName&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取当前事件管道所处理的请求消息&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Mode&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取插件执行模式：同步执行还是异步执行.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OperationCreatedOn&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td rowspan="2" valign="top"&gt;&lt;p&gt;在与Azure云进行集成的时候用到的。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OperationId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OrganizationId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取实体实例所属组织的GUID.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OrganizationName&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取实体实例所属组织的唯一名称.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OutputParameters&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取平台核心操作完成后的响应消息参数.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;OwningExtension&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取相关联的&lt;strong&gt;SdkMessageProcessingingStep&lt;/strong&gt;对象.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;PostEntityImages&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td rowspan="2" valign="top"&gt;&lt;p&gt;主要用于UpdateRequest消息中，分别获取核心操作之前以及之后实体的快照、映像信息&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;PreEntityImages&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;PrimaryEntityId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;事件管道正在处理的实体实例的GUID&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;PrimaryEntityName&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;事件管道正在处理的实体的逻辑名称.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;RequestId&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;事件管道正在处理的请求的GUID.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;SharedVariables&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;p&gt;获取/设置插件之间传递的自定义属性值.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 当触发了插件订阅的事件时，CRM会创建、填充执行上下文，并将其作为Execute方法的输入参数，传递给Execute方法，从而，插件执行代码就可以使用这些上下文信息了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在上下文中，有几个非常重要的属性，是插件代码中经常会使用到的：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 输入参数InputParameters以及输出参数OutputParameters，这两个属性的基本信息已经在上面的列表中列出了，在此不赘述。下面主要看一下这两个属性的类型：ParameterCollection，ParameterCollection究其根本而言，是IEnumerable&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt;类型，即可遍历的键值对集合。由此，在插件代码中通过给定键值，就可以访问对应的数据值了，而键值就是各类请求消息中的公共属性的名称。例如CreateRequest中，有一个属性名为Target，包含了待创建的实体实例信息，是Entity类型，那么若要在CreateRequest触发的插件中访问带创建的实体实例信息，就可以使用如下代码获取：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;Entity entity = (Entity)context.InputParameters[&amp;ldquo;Target&amp;rdquo;];&lt;/div&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于OutputParameters属性，也是类似的，只不过键值名称信息来自于相关的响应信息属性，而不再是请求消息中的属性名称了，其访问的方式和InputParameters属性的访问类似，不再赘述。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 前期映像PreEntityImages和后期映像PostEntityImages，存储了平台核心操作之前与之后的快照。可以在插件注册的过程中，指定快照中需要存储的属性。需要注意的是，某些事件是缺少前期或者后期映像的。例如对于创建，是没有前期映像的，对于Delete是没有后期映像的。映像的类型是EntityCollection，本质和ParameterCollection类型是类似的，可以通过给定键值访问对应的映像数据，而键值的名称是在注册插件，设定映像的名称时候设定的。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 除了执行上下文以外，绝对大多数情况下，还需要访问MS CRM系统的组织服务，那么可以通过从serviceProvider对象中获取组织服务工厂，而后由组织服务工厂的CreateOrganizationService方法创建组织服务的实例。代码可以参看上面的样例代码。在此不赘述。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面列出了一个简单的插件，执行于客户Account的Pre Create事件上。处理的业务逻辑是，如果End User没有为客户编码字段赋值，那么插件就为该字段赋一个随机值。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Microsoft Dynamics CRM的命名空间之一&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;using&lt;/span&gt; Microsoft.Xrm.Sdk;&lt;br /&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;namespace&lt;/span&gt; Microsoft.Crm.Sdk.Samples&lt;br /&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;class&lt;/span&gt; AccountNumberPlugin: IPlugin&lt;br /&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt;     {&lt;br /&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; Execute(IServiceProvider serviceProvider)&lt;br /&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt;         {&lt;br /&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt;             &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 获取执行上下文&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt;             IPluginExecutionContext context =&lt;br /&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt;                 (IPluginExecutionContext)serviceProvider.GetService(&lt;span style="color: #0000ff;"&gt;typeof&lt;/span&gt;(IPluginExecutionContext));&lt;br /&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt;             &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; InputParameters属性包含所有输入参数数据&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt;             &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (context.InputParameters.Contains(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Target&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;) &amp;amp;&amp;amp;&lt;br /&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt;                 context.InputParameters[&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Target&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;] &lt;span style="color: #0000ff;"&gt;is&lt;/span&gt; Entity)&lt;br /&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt;             {&lt;br /&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt;                 &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 从输入参数中获取Target参数&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt;                 Entity entity = (Entity)context.InputParameters[&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Target&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;];&lt;br /&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt;                 &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;检测输入的Target参数，判断其逻辑名称是否是account.&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt;                 &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (entity.LogicalName == &lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;account&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;) &lt;br /&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt;                 {&lt;br /&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt;                     &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 判断客户记录的客户编码字段accountnumber是否有值&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt;                     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (entity.Attributes.Contains(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;accountnumber&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;) == &lt;span style="color: #0000ff;"&gt;false&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt;                     {&lt;br /&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt;                         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 没有客户编码，那么赋一个随机数字&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt;                         Random rndgen = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; Random();&lt;br /&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt;                         entity.Attributes.Add(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;accountnumber&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;, rndgen.Next().ToString());&lt;br /&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt;                     }&lt;br /&gt;&lt;span style="color: #008080;"&gt;33&lt;/span&gt;                     &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;34&lt;/span&gt;                     {&lt;br /&gt;&lt;span style="color: #008080;"&gt;35&lt;/span&gt;                         &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 抛出一个错误，注意，错误的类型！&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt;36&lt;/span&gt;                         &lt;span style="color: #0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; InvalidPluginExecutionException(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;The account number can only be set by the system.&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;37&lt;/span&gt;                     }                    &lt;br /&gt;&lt;span style="color: #008080;"&gt;38&lt;/span&gt;                 }&lt;br /&gt;&lt;span style="color: #008080;"&gt;39&lt;/span&gt;             }&lt;br /&gt;&lt;span style="color: #008080;"&gt;40&lt;/span&gt;         }&lt;br /&gt;&lt;span style="color: #008080;"&gt;41&lt;/span&gt;     }&lt;br /&gt;&lt;span style="color: #008080;"&gt;42&lt;/span&gt; }&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上面就是一个简单的插件类的代码，仅仅是一个样例，具体的插件代码编写，还是要根据实际的业务情况确定的。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2339490.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2339490.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/StoneGarden/archive/2012/02/02/2336147.html</id><title type="text">MS CRM 2011的自定义和开发（11）&amp;mdash;&amp;mdash;插件(plugin)开发（一）</title><summary type="text">在MS CRM 2011的自定义和开发（8）——扩展框架以及扩展点介绍中介绍了扩展点，在MS CRM 2011的自定义开发（10）的几篇文章中介绍了Microsof Dynamics CRM 201...</summary><published>2012-02-02T11:34:00Z</published><updated>2012-02-02T11:34:00Z</updated><author><name>石头居</name><uri>http://www.cnblogs.com/StoneGarden/</uri></author><link rel="alternate" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/02/2336147.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/StoneGarden/archive/2012/02/02/2336147.html"/><content type="html">&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2011/11/20/2256441.html"&gt;MS CRM 2011的自定义和开发（8）——扩展框架以及扩展点介绍&lt;/a&gt;中介绍了扩展点，在MS CRM 2011的自定义开发（10）的几篇文章中介绍了Microsof Dynamics CRM 2011中的发现服务DiscoveryService以及组织服务OrganizationService，从而完成了开发方面基础知识的准备工作，在本章，以及后续的几章将会介绍如何利用这些服务，在扩展点上进行扩展开发。本章介绍插件开发内容。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 插件，Plugin，在之前的版本也被称作Callout，中文也可以称作是业务逻辑扩展。在SDK中，对插件的定义是：插件是可与 Microsoft Dynamics CRM 2011 和 Microsoft Dynamics CRM Online 集成的自定义业务逻辑（代码），用于修改或增加平台的标准行为。也可以将插件认为是针对 Microsoft Dynamics CRM 平台触发的事件的处理程序。您可以让插件订阅（也称为注册）已知事件集，以便在事件发生时运行您的代码。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 个人的理解，插件，可以和数据库中的触发器，面向对象编程中的事件处理函数进行类比。触发器，可以由对数据表进行Update、Insert或Delete的操作触发，从而开始执行。事件处理函数，基于消息而执行。而插件，会根据注册时订阅的消息而触发执行。而且，可以被订阅的消息非常之多，除了CRUD操作，还包括有其他分派、共享等等MS CRM系统中具有业务语义的消息。此外，插件也可以有类似于触发器中Before、After等处理阶段的概念，被称为事件管道阶段。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在介绍插件开发之前，首先要了解微软CRM的事件处理框架。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MS CRM的事件处理框架包括以下一些内容：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;事件处理子系统：该子系统提供执行插件、工作流的统一的方法，从而保障了可靠性、功能集以及灵活性；&lt;/p&gt; &lt;p&gt;事件框架API：允许以插件、工作流活动的形式开发自定义业务逻辑，从而扩展系统的功能；&lt;/p&gt; &lt;p&gt;部署API：完成插件以及自定义工作流活动程序集的部署操作，尤其是可以将插件、工作流程序集部署到CRM的数据库中，在集群环境下非常有意义，避免了服务器之间的文件拷贝工作；&lt;/p&gt; &lt;p&gt;向后兼容性：允许V4版本的插件运行于CRM2011中；  &lt;p&gt;同步/异步：可以作为主CRM流程的一个组成部分被执行，也可以放入异步队列，被异步执行；&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Dynamics CRM 事件处理子系统根据消息管道执行模型执行插件。MS CRM Web应用程序中的用户操作或者插件或其他应用程序执行的 SDK 方法调用会导致将消息发送到组织服务。被传递给组织服务的消息包含业务实体信息和核心操作信息，该消息是通过事件执行管道传递的，平台核心操作和任何注册的插件都可以在事件执行管道中读取或修改它。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 事件处理体系架构如下图所示。&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/20120202193327847.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://images.cnblogs.com/cnblogs_com/StoneGarden/201202/201202021933291635.jpg" width="558" height="439"&gt;&lt;/a&gt;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 事件执行管道可以使用同步或者异步两种方式处理事件。平台核心操作以及注册为同步执行的插件会立即执行，而对于注册为异步执行的插件，CRM系统会把事件处理放入到异步队列中，而后，由MS CRM的异步处理服务进行管理控制。  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 事件管道阶段，事件执行管道分为多个阶段，以平台核心操作作为分界，在平台核心操作之前执行的阶段被称为前置事件（前期事件、Pre-Event），在平台核心操作之后执行的阶段被成为后置事件（后期事件、Post-Event）。下表是事件管道阶段的详细信息：&lt;/p&gt; &lt;table border="1" cellspacing="1" cellpadding="0"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;&lt;b&gt;事件 &lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;&lt;b&gt;阶段名称 &lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;&lt;b&gt;阶段编号 &lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;&lt;b&gt;说明 &lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;前期事件&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;前期验证&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;10&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;管道中的一个阶段，其中的插件在主系统操作之前执行。在此阶段注册的插件可能会在数据库事务外部执行。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;前期事件&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;前期操作&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;20&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;管道中的一个阶段，其中的插件在主系统操作之前执行。在此阶段注册的插件将在数据库事务内部执行。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;平台核心操作&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;主操作&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;30&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;系统的事务内主操作，例如创建、更新和删除等等。在该阶段中不可以注册自定义插件。仅供内部使用。 &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;后期事件&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;后期操作&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;40&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;管道中的一个阶段，其中的插件在主系统操作之后执行。在此阶段注册的插件将在数据库事务内部执行。&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;后期事件&lt;/p&gt;&lt;/td&gt; &lt;td&gt; &lt;p&gt;后期操作（已弃用）&lt;/p&gt;&lt;/td&gt; &lt;td width="63"&gt; &lt;p&gt;50&lt;/p&gt;&lt;/td&gt; &lt;td width="602"&gt; &lt;p&gt;管道中的一个阶段，其中的插件在主系统操作之后执行。在此阶段注册的插件可能会在数据库事务外部执行。此阶段仅支持基于 Microsoft Dynamics CRM 4.0 的插件。 &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 由于可以在一个阶段注册多个插件，换言之，多个插件可以订阅一个事件，那么在实际运行中，当调用了CRM组织服务的方法时，作为参数传递给方法的消息会被打包为OrganizationRequest消息，并交由管道进行处理。管道会将消息传递给订阅了该事件的第一个插件，第一个插件执行过程中，会对消息进行读取、修改等操作，该插件执行完成后，被处理后的消息将会继续在管道中执行——被管道传递给下一个插件，以此类推。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在MS CRM 2011中，新增加的一个特性就是，在编号20至编号40三个阶段是处于数据库事务中的，从而在一定程度上保证了数据操作的完整性。假设插件处于阶段20或者阶段40，如果插件抛出了异常，那么将会回滚整个事务。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/StoneGarden/aggbug/2336147.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/StoneGarden/archive/2012/02/02/2336147.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
