【问题标题】:How to Execute FetchXML in CRM 2011 using a CRM 2011 webservice and JavaScript?如何使用 CRM 2011 Web 服务和 JavaScript 在 CRM 2011 中执行 FetchXML?
【发布时间】:2011-08-18 03:08:44
【问题描述】:

我想在 CRM 2011 环境中使用 CRM 2011 SOAP Web 服务 和 JavaScript 执行 FetchXML 查询。

我找到了很多文章like this one 展示了如何使用在 2011 环境中仍然可用的 4.0 网络服务,但我不想这样做。

This link 似乎表明 IOrganizationService.RetrieveMultiple 可以处理 FetchXML。但是,我不想为此使用托管代码。

我遇到了this link,它基本上显示了我想在 RetrieveMultiple 函数中执行的操作,但我希望能够传入我编写的现有 FetchXML,而不是新的过滤器表达式。

【问题讨论】:

    标签: javascript dynamics-crm-2011 fetchxml


    【解决方案1】:

    要使用 JavaScript 执行 fetchxml 查询,可以使用一系列框架/库:

    这些库不是手动编写代码,而是提供了一种简单的方法来执行多个操作并访问结果。但请注意,并非所有库(当前)都支持跨浏览器(2012 年第 2 季度)。

    【讨论】:

    • 谢谢 Thuld。我认为这些在我发布问题时不可用,但现在看起来有一些不错的选择。
    • 关于 3 的优点/缺点的任何 cmet?我想我应该开始使用一个,但想知道我应该考虑什么才能决定......
    • 好的,我是 CrmFetchKit 的作者,所以我更喜欢这个 :) 但是,一如既往,这取决于。另一方面,XrmServiceToolkit 支持更多操作/消息,CrmFetchKit 提供跨浏览器支持。
    • 好消息:CrmFetchKit 无需任何更改即可支持 CRM 2013,它可以正常工作 :)
    【解决方案2】:

    从您发布到Microsoft SDK 的链接中,您将看到如何连接到 ODATA 服务。您可能已经发现,ODATA 不允许您执行 fetch。

    相反,您需要使用 SOAP 服务 (/XrmServices/2011/Organization.svc),并使用 Retrieve Multiple 传递您的提取。

    这里更详细地介绍了通过 JavaScript 使用 2011 服务:http://blog.customereffective.com/blog/2011/05/execute-fetch-from-javascript-in-crm-2011.html

    这是另一篇博客文章,它解析返回的 XML 并构建一个易于使用的 JavaScript 对象:http://blog.customereffective.com/blog/2011/05/parsing-and-consuming-the-crm-2011-soap-service-inside-javascript.html

    2011 年的组织服务在它的回报上有很大的不同,所以它不会是你的 4.0 东西的即插即用;但是,2011 端点有很多不错的改进。

    【讨论】:

    • 我正在使用的迁移将 Ascentium CRM Helper 用于 4.0 Web 服务。我为 2011 Web 服务创建了一个类似的帮助器,它返回与 Ascentium 帮助器相同的业务对象。我认为转换为业务对象还有改进的余地,但到目前为止它似乎适用于我当前的项目。我有兴趣阅读您即将发布的帖子。也许我们可以比较我们的方法?
    • 哇,我喜欢 Ascentium 服务,而且奇怪的是有一些类似的元素,所以希望这些变化是最小的。这只是现在的 Fetch。顺便说一句,如果你不在线使用,那么你可以注释掉他们的一些 CreateXMLHTTP 代码并在本地连接而无需发布(这很方便)。您应该能够复制 CreateXMLHTTP 代码和 3 个辅助类并将它们插入我发布的内容中。
    【解决方案3】:

    this MSDN article 的“捕获示例 HTTP 请求和响应”部分概述了如何获取从托管代码发送到 CRM 2011 的 SOAP 消息。

    this MSDN article 的“执行查询”部分提供了在托管代码中使用 2011 年的 IOrganizationService.RetrieveMultiple 来执行 FetchXML 查询的示例。

    使用这两个示例,您可以为 RetrieveMultiple 提取包含 FetchXML 查询的示例 SOAP 消息。

    the first MSDN article 的“创建 JScript 库”部分展示了如何在 JavaScript 中针对 2011 SOAP 端点执行执行请求。将此示例中的 Assign SOAP 请求替换为您通过执行托管代码获得的 RetrieveMultiple SOAP 消息。

    这使您能够在 JavaScript 中针对 2011 SOAP 端点执行 FetchXML 请求。

    以下是我使用上述信息编写的 JavaScript 库中的一些 sn-ps:

    (function (window, undefined) {
        var _window = undefined;
    
        if (window.Xrm)
            _window = window;
        else if (window.parent.Xrm)
            _window = window.parent;
        else throw new Error("Unable to determine proper window");
    
        (function (Crm) {
            (function (Service, $, JSON, Xrm) {
                if (!Xrm)
                    throw new Error("Unable to locate Xrm");
                if (!JSON)
                    throw new Error("Unable to locate JSON");
                if (!$)
                    throw new Error("Unable to locate jQuery");
    
                Service.Create = function (ODataSetName, EntityObject) {
                    if (!EntityObject) {
                        throw new Error("EntityObject is a required parameter");
                        return;
                    }
                    if (!ODataSetName) {
                        throw new Error("ODataSetName is a required parameter");
                        return;
                    }
                    var jsonEntityObject = JSON.stringify(EntityObject);
    
                    var req = new XMLHttpRequest();
                    req.open("POST", Service.GetODataEndPoint() + "/" + ODataSetName, false);
                    req.setRequestHeader("Accept", "application/json");
                    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                    req.onreadystatechange = function () {
                        debuggingCallBack(this);
                    };
    
                    req.send(jsonEntityObject);
    
                };
                function debuggingCallBack(req) {
                    if (req.readyState == 4 /* complete */) {
                        if (req.status == 201 || req.status == 204 || req.status == 1223) {
                            //Success
                            //201 = create
                            //204 = update
                            //1223 = delete
                        }
                        else {
                            //Failure
                            debugger;
                        }
                    }
                };
    
    
                Service.Fetch = function (FetchXML) {
                    var request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
                    request += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
                    request += "<s:Body>";
                    request += "<RetrieveMultiple xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
                    request += "<query i:type=\"a:FetchExpression\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
                    request += "<a:Query>";
                    request += Service.FetchEncode(FetchXML);
                    request += "</a:Query>";
                    request += "</query>";
                    request += "</RetrieveMultiple>";
                    request += "</s:Body>";
                    request += "</s:Envelope>";
    
                    var req = new XMLHttpRequest();
                    req.open("POST", Service.GetSOAPEndPoint(), false)
                    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/RetrieveMultiple");
                    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
                    req.setRequestHeader("Content-Length", request.length);
                    req.send(request);
    
                    results = Service.GetResults(req.responseXML);
    
                    return results;
                };
                Service.Delete = function (ODataSetName, EntityID) {
                    if (!EntityID) {
                        throw new Error("EntityID is a required parameter");
                        return;
                    }
                    if (!ODataSetName) {
                        throw new Error("ODataSetName is a required parameter");
                        return;
                    }
    
                    var req = new XMLHttpRequest();
                    req.open("POST", Service.GetODataEndPoint() + "/" + ODataSetName + "(guid'" + EntityID + "')", false)
                    req.setRequestHeader("Accept", "application/json");
                    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                    req.setRequestHeader("X-HTTP-Method", "DELETE");
                    req.onreadystatechange = function () {
                        debuggingCallBack(this);
                    };
                    req.send();
    
                };
    
    
                Service.GetServerUrl = function () {
                    var serverUrl = null;
                    serverUrl = Xrm.Page.context.getServerUrl();
                    if (serverUrl.match(/\/$/)) {
                        serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                    }
                    return serverUrl;
                };
                Service.GetODataEndPoint = function () {
                    return Service.GetServerUrl() + "/XRMServices/2011/OrganizationData.svc";
                };
                Service.GetSOAPEndPoint = function () {
                    return Service.GetServerUrl() + "/XRMServices/2011/Organization.svc/web";
                };
    
                Service.GetResults = function (responseXML) {
                    var sFetchResult = responseXML.selectSingleNode("//RetrieveMultipleResult").xml;
    
                    var oResultDoc = new ActiveXObject("Microsoft.XMLDOM");
                    oResultDoc.async = false;
                    oResultDoc.loadXML(sFetchResult);
    
                    var oResults = new Array(oResultDoc.firstChild.firstChild.childNodes.length);
    
                    var iLen = oResultDoc.firstChild.firstChild.childNodes.length;
                    for (var i = 0; i < iLen; i++) {
    
                        var oResultNode = oResultDoc.firstChild.firstChild.childNodes[i];
                        var oBE = new BusinessEntity(oResultNode.selectSingleNode("//a:LogicalName").text);
    
                        var iLenInner = oResultNode.firstChild.childNodes.length;
                        for (var j = 0; j < iLenInner; j++) {
                            var oRA = new Object();
    
                            var value = null;
                            if (oResultNode.firstChild.childNodes[j].lastChild.childNodes.length == 3) {
                                if (oResultNode.firstChild.childNodes[j].lastChild.getElementsByTagName("a:Id").length == 1)
                                    value = oResultNode.firstChild.childNodes[j].lastChild.getElementsByTagName("a:Id")[0].text;
                                if (oResultNode.firstChild.childNodes[j].lastChild.getElementsByTagName("a:Value").length == 1)
                                    value = oResultNode.firstChild.childNodes[j].lastChild.getElementsByTagName("a:Value")[0].text;
                            }
                            if (!value)
                                value = oResultNode.firstChild.childNodes[j].lastChild.text;
    
                            oRA["value"] = value;
    
                            oBE.attributes[oResultNode.firstChild.childNodes[j].firstChild.firstChild.text] = oRA;
                        }
    
                        oResults[i] = oBE;
                    }
                    return oResults;
                };
    
                Service.BusinessEntity = function BusinessEntity(sName) {
                    this.name = sName;
                    this.attributes = new Object();
                };
    
                Service.FetchEncode = function (FetchXML) {
                    var c;
                    var HtmlEncode = '';
    
                    if (FetchXML == null) {
                        return null;
                    }
                    if (FetchXML == '') {
                        return '';
                    }
    
                    for (var cnt = 0; cnt < FetchXML.length; cnt++) {
                        c = FetchXML.charCodeAt(cnt);
    
                        if (((c > 96) && (c < 123)) ||
                                ((c > 64) && (c < 91)) ||
                                (c == 32) ||
                                ((c > 47) && (c < 58)) ||
                                (c == 46) ||
                                (c == 44) ||
                                (c == 45) ||
                                (c == 95)) {
                            HtmlEncode = HtmlEncode + String.fromCharCode(c);
                        }
                        else {
                            HtmlEncode = HtmlEncode + '&#' + c + ';';
                        }
                    }
    
                    return HtmlEncode;
                };
            } (Crm.Service = Crm.Service || {}, _window.jQuery, _window.JSON, _window.Xrm));
        } (_window.Crm = _window.Crm || {}));
    } (window));
    

    【讨论】:

    • 虽然此方法允许您在 JavaScript 中针对 2011 SOAP 端点执行 FetchXML 请求,但它不会以与 4.0 Web 服务相同的格式返回 XML。我希望我可以将 CRM 4.0 到 2011 迁移项目的 FetchXML 调用更新,但这不会那么容易。
    • Service.Fetch函数中,“results”在返回前定义在哪里?
    • 好收获。我会查看源代码并与您联系。
    • 抱歉花了这么长时间才更新。我已经更新了代码以包含整个 javascript 文件。这应该更容易恢复。 GetResults 函数并非万无一失,因此如果有人对如何改进它提出建议,我会很高兴听到这些。
    【解决方案4】:

    “REST 是一种架构风格,其中每个资源都使用唯一的 URI 来寻址。” http://msdn.microsoft.com/en-us/library/gg334279.aspx

    如果您需要使用 FetchXml,您将无法使用 REST 端点。

    另一种方法是按照您在 CRM4 示例中看到的那样构建 SOAP 消息。我自己还没有这样做,但也许你可以使用像 Fiddler 这样的工具来查看 SOAP 消息的样子,这样你就可以在你修改了 FetchXml 的环境中复制它们。

    无论如何,现在只是一个想法。让我知道它是怎么回事,如果你设法解决它,也许可以发布你的解决方案。

    【讨论】:

    • 感谢您对 REST 端点的说明。一旦我弄清楚这一点,我一定会回帖。
    猜你喜欢
    • 2011-11-24
    • 1970-01-01
    • 2013-03-02
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2014-02-11
    • 1970-01-01
    相关资源
    最近更新 更多