在CRM中,更多的时候我们为了便于部署和提高用户体验都会选择用Javascript在客户端调用Web Service.其实在服务器端开发plugin我们仍然可以达到类似的效果,并且我们可以很方便的处理通过Web Service返回的结果,但用Javascript最主要的好处是很容易部署。众所周知,在CRM里的二次开发大多集中于定制,我们将写的Javascript及在其客户端事件中调用的Javascript方法都可以方便的Export到Customization文件中,这样在部署到生产机器上时我们无需做其他的事情。

      和普通的Javascript Client Side调用Web Service一样,过程都是构造一个请求的SOAP消息,然后通过创建XMLHttp对象将请求发送给Web Service,然后通过XMLHttp带回的结果解析XML从而刷新界面。其实和服务器端调用Web Service的过程相同,我们不妨来做个比较,这样可能更容易帮助大家理解Client-Side Calling的过程:

       1). 构建QueryExpression对象来准备请求的对象和请求返回的对象属性。       

        QueryExpression query = new QueryExpression();
        query.ColumnSet = new AllColumns();
        query.EntityName = EntityName.account.ToString();


        2). 给构建的请求对象附加过滤条件
        FilterExpression filter = new FilterExpression();
        query.Criteria = filter;

        ConditionExpression hasEmailAddress = new ConditionExpression();
        filter.Conditions = new ConditionExpression[] { hasEmailAddress };

        hasEmailAddress.AttributeName = "emailaddress1";
        hasEmailAddress.Operator = ConditionOperator.NotNull;


        3). 调用CrmService的RetrieveMultiple或者RetrieveSingle方法来发出请求。
        
CrmLogService service = new CrmLogService();
        service.Url = "http://stunnwarecrm/mscrmservices/2006/crmservice.asmx";
        service.Credentials = CredentialCache.DefaultCredentials;
        service.SoapMessageSerializationFinished += new SoapMessageEventHandler(service_SoapMessageSerializationFinished);
        service.RetrieveMultiple(query);
      服务端调用Web Service的三个步骤其实和所有调用Web Service的方法也没有什么不同,除了需要按照CRM的写法来声明ColumnSet作为返回的对象属性组,用ConditionOperator 作为条件表达式的关系符号以及略显繁琐的ConditionExpression外无非就是声明一个参数,并调用Service.RetrieveMultiple而已。理解了这个过程我们可以很轻松的把以上托管代码翻译为Javascript代码,所不同的是在javascript里边我们需要将其拼接为一个Evelop消息(因为代理类帮我们在服务器端处理了这个过程,而在javascript里我们却无法得到,所以必须通过手工来创建)。一下代码演示了如何获取一组Account对象:

//call web service to retrieve the account
var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope//" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance/" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema/">" +
GenerateAuthenticationHeader() +
"  <soap:Body>" +
"    <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices/">" +
"      <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query/" xsi:type=\"q1:QueryExpression\">" +
"        <q1:EntityName>account</q1:EntityName>" +
"        <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
"          <q1:Attributes>" +
"            <q1:Attribute>name</q1:Attribute>" +
"            <q1:Attribute>accountid</q1:Attribute>" +
"          </q1:Attributes>" +
"        </q1:ColumnSet>" +
"        <q1:Distinct>false</q1:Distinct>" +
"        <q1:Criteria>" +
"          <q1:FilterOperator>And</q1:FilterOperator>" +
"          <q1:Conditions>" +
"            <q1:Condition>" +
"              <q1:AttributeName>firstname</q1:AttributeName>" +
"              <q1:Operator>Like</q1:Operator>" +
"              <q1:Values>" +
"                <q1:Value xsi:type=\"xsd:string\">%A%</q1:Value>" +
"              </q1:Values>" +
"            </q1:Condition>" +
"          </q1:Conditions>" +
"        </q1:Criteria>" +
"      </query>" +
"    </RetrieveMultiple>" +
"  </soap:Body>" +
"</soap:Envelope>" +
"";

要注意的是必须加入对CRM提供的Global Methode GenerateAuthenticationHeader()的引用,它将给这段请求代码加入有关验证身份的代码。我们仍然只需要生成Query,然后声明需要返回哪些列(如果返回所有列可以选择<q1:ColumnSet xsi:type=\"q1:AllColumn\">" ),然后给请求添加过滤条件。接下来便可以把信发给Web Service并等待通知了:

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","
http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
alert(resultXml.xml);

返回的结果同样是以XML形式封装的,接下来所要做的就是解析返回的resultXML了。

var entityNodes = resultXml.selectNodes("//RetrieveMultipleResult/BusinessEntities/BusinessEntity");

for (var i = 0; i < entityNodes.length; i++) {

    // Access the current array element
    var entityNode = entityNodes[i]; 

    var accountidNode = entityNode.selectSingleNode("q1:accountid");
    var nameNode = entityNode.selectSingleNode("q1:name");


    var accountid = (accountidNode == null) ? null : accountidNode.text;
    var name = (nameNode == null) ? null : nameNode.text;

    // finally display the values.
    alert(name + ", " + accountid);
}

     有些不方便的是我们通常还需要用到多个对象(LinkEntity来关联),多个过滤条件等,对于大小写敏感且无自动感知的javascript来说很难写。既然我们已经了解了如何客户端调用CRM Web Service,这里我们再给大家介绍一个工具用来简化上述一系列问题:用FetchXmlWizard工具来生成请求的XML(用来检索对象的语法称为FetchXML),并将验证过的FetchXML发给JavaScript Web Service Calls工具来生成标准的Client-side javascript代码。这两个工具你都可以很方便的在http://www.stunnware.com/网站下载。下边简单说说如何来用这两个工具:

1. 首先打开FetchXMLWizard.exe文件,在弹出的链接CRM Server的窗口中输入相关信息,然后确定。

        

2. 在空白区域右击并选择Add Main Entity(only choice now),然后再弹出的选择实体框中选择一个实体,这里我们选择Account.

3. 右键点击Account并选择Select Attributes, 在弹出的对话框中选择你想要选择的属性。

4,接下来我们可以通过右键来添加任意我们想要的东西,比如Link Entity, Add Filter等,都比较简单,我们不一一概述。需要提及的一点是Add Filter,在Add Filter之后我们需要再右键点击来给Filter加入Condition,因为一个Filter实际上是包含多个Condition的并且每个Condition之间还有关系。在Specify Condition窗体中选择相应的字段和关系,并输入你的条件值即可,在这里我们可以看到很多关系(根据类型的不同,关系也会有所改变)

5. 一切做完之后,转到Fetch XML tab页我们就看到生成的FetchXML了,这里我们已经成功了一大半(你仍然可以通过选择(Query->Execute)或F5来验证你的结果。)

6. 最后一步了,我们将生成的FetchXML交给Javascript Web Service Call tool去生成Javascript code. 这个工具是个.NET项目,你首先需要打开解决方案并更改其对web service的正确引用,并在app.config中将CRM server的地址更改正确。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        。。。。。。

     </configSections>
    <applicationSettings>
        <Stunnware.Tools.Properties.Settings>
            <setting name="JavaScript_Web_Service_Calls_CrmService3_CrmService"
                serializeAs="String">
                <value>http://SERVER_NAME/MSCrmServices/2007/CrmService.asmx</value>
            </setting>
        </Stunnware.Tools.Properties.Settings>
    </applicationSettings>
</configuration>

然后运行程序,将上边生成的FetchXML拷贝到request栏里,点击Start按钮

ok,大功告成, 看看你的Javascript code吧:)

posted on 2008-10-06 23:04  Allan.  阅读(3006)  评论(3编辑  收藏  举报