AX2009 调用 Dynamics CRM 2011 web service

Dynamics CRM 2011一共提供了如下几类services:

1.以.svc为扩展名的基于WCF的服务(位于XRMServices目录下):organization.svc, Discovery.svc

2.以.asmx为扩展名的4.0类型的服务(位于MSCRMServices目录下): crmservice.asmx, crmdeploymentservice.asmx, metadataservice.asmx

3.OData服务(位于XRMServices目录下): OrganizationData.svc

AX2009的局限性:

1. 只能兼容CLR 2.0 (包括3.0, 3.5)

2. 不支持含有CLR Generics类型数据

通常我们使用VS.NET来生成Proxy Classes的办法有这么几种:

1. Add Web Reference

2. Add Service Reference

这2者之间的区别:

“The low-level answer here is that a Web Reference will create a client proxy class that allows your code to talk to a Web Service that is described via WSDL and communicates via SOAP or HTTP GET (other posters indicate that it is only ASMX, but Web References can also talk to Java-based Web Services or Python-based or Ruby so long as they all talk WSDL and conform to the WS-I interoperability standard).

A Service Reference will create a client proxy class that communicates with a WCF-based service : regardless of whether that WCF service is a Web Service or not.”  - 引自 difference-between-web-reference-and-service-reference

Dynamics CRM 2011 实现的.svc类型的服务通过Add Service Reference的方式是没法在X++里调用的,因为其使用了CLR Generics类型的数据; 即使使用Add Web Reference的方式能成功生成对应的proxy classes, 但是运行的时候CRM Platform会拒绝处理请求,因为这种方式生成的proxy classes的数据根WCF不兼容,CRM Platform没法处理。

为了能在AX2009里面调用CRM 2011, 我验证可行的办法是:

1. 使用OData.svc. 示例代码:

static void GetCRMContact(Args _args)
{

    System.Net.HttpWebRequest   httpRequest  = null;
    System.Net.HttpWebResponse  httpResponse = null;
    System.Net.CookieCollection cookies      = null;
    CLRObject                   clro         = null;
    System.Net.NetworkCredential credential;
    System.IO.Stream stream;
    System.IO.StreamReader reader;
    str msg;
    InteropPermission ipCLR;
    ;
    ipCLR=new InteropPermission(InteropKind::ClrInterop);
    ipCLR.assert();
    clro         = System.Net.WebRequest::Create("https://localhost:5555/CRM2011RTW/XRMServices/2011/OrganizationData.svc/ContactSet?$select=FullName,Address1_Country");
    httpRequest  = clro;

    credential = new System.Net.NetworkCredential("Administrator","P@ssw0rd","CliffCRM");
    httpRequest.set_Credentials(credential);
    httpResponse = httpRequest.GetResponse();
    stream=httpResponse.GetResponseStream();
    reader= new System.IO.StreamReader(stream);
    msg=reader.ReadToEnd();
    info(msg);

    CodeAccessPermission::revertAssert();

}

2. 建立一个C#类型的Class Library项目(基于.NET 3.5), 然后Add Web Reference 到/MSCRMServices/2007/CrmService.asmx?wsdl">https://<yourCRMsite>/MSCRMServices/2007/CrmService.asmx?wsdl

在AX里面加入Reference. 如果是在AX Client的Job里调用,需要把ClassLibrary 生成的DLL复制到\Program Files\Microsoft Dynamics AX\50\Client\Bin目录下, ClassLibrary的config文件可以重命名为Ax32.exe.config; 如果是在AX server class里调用C# ClassLibrary,那么需要把ClassLibrary 生成的DLL复制到\Program Files\Microsoft Dynamics AX\50\Server\<InstanceName>\Bin目录下.

示例代码如下:

static void TestCRMSOAPJob(Args _args)
{
    str strError;
    CLRObject exc;
    CLRObject clrExcMessage;
    CLRObject innerExc;

    XRMServicesInterface.XrmSdk     xrmInterface;
    XRMServicesInterface.CrmSDK.BusinessEntityCollection        entityCollection;
    XRMServicesInterface.CrmSDK.BusinessEntity[]                entities;
    XRMServicesInterface.CrmSDK.BusinessEntity                  entity;
    XRMServicesInterface.CrmSDK.account                         account;
    XRMServicesInterface.CrmSDK.Key    key;
    XRMServicesInterface.CrmSDK.Lookup lookup;
    XRMServicesInterface.CrmSDK.Picklist picklist;
    XRMServicesInterface.CrmSDK.CrmMoney crmMoney;
    Guid myGuid;
    CLRObject tempCLRObj;
    System.String clrStr;
    str axStr;
    System.Int32    recordLen;
    int axLen;
    int axInt;
    System.Decimal decimal;

    System.Collections.IEnumerator          iEnumerator;
    boolean                                 success;

   ;
    try
    {
        new InteropPermission(InteropKind::ClrInterop).assert();
        xrmInterface = new XRMServicesInterface.XrmSdk();

        entityCollection    = new XRMServicesInterface.CrmSDK.BusinessEntityCollection();
        entityCollection    = xrmInterface.RetrieveCRMAccount();

        entities       = entityCollection.get_BusinessEntities();
        if(CLRInterop::isNull(entities)) return;

        recordLen= entities.get_Length();
        axLen=recordLen;
        if(axLen > 0){

          iEnumerator= entities.GetEnumerator();
          success         = iEnumerator.MoveNext();
          while (success){
          entity  = iEnumerator.get_Current();
          tempCLRObj=entity;
          account= tempCLRObj;

          clrStr=account.get_name();
          if(!CLRInterop::isNull(clrStr)){
          axStr=clrStr;
          info(strfmt("ACCOUNT: name=%1",axStr));
           }
            key=account.get_accountid();
             if(!CLRInterop::isNull(key)){
            myGuid=key.get_Value();
            info(strfmt("      ATTRIBUTE AccountId=%1",myGuid));
            }

            lookup=account.get_owninguser();
            if(!CLRInterop::isNull(lookup)){
            myGuid=lookup.get_Value();

            info(strfmt("      ATTRIBUTE OwningUser=%1",myGuid));
            }

            picklist=account.get_accountclassificationcode();
            if(!CLRInterop::isNull(picklist)){
             axInt=picklist.get_Value();
             info(strfmt("      ATTRIBUTE accountclassificationcode=%1",axInt));
            }

          picklist=account.get_accountcategorycode();
          if(!CLRInterop::isNull(picklist)){
             axInt=picklist.get_Value();
             info(strfmt("      ATTRIBUTE accountcategorycode=%1",axInt));
          }

          clrStr=account.get_accountnumber();
          if(!CLRInterop::isNull(clrStr)){
          axStr=clrStr;
          info(strfmt("      ATTRIBUTE AccountNumber=%1",axStr));
          }

          crmMoney=account.get_aging60();
          if(!CLRInterop::isNull(crmMoney)){
          decimal=crmMoney.get_Value();
          info(strfmt("      ATTRIBUTE aging60=%1",decimal));
                           }

          success = iEnumerator.MoveNext();
          }

        }
       CodeAccessPermission::revertAssert();

    }
    catch(Exception::CLRError)
    {
       // throw error(AifUtil::getClrErrorMessage());
       // BP Deviation Documented
        exc = CLRInterop::getLastException();

        if(exc)
        {
           info(exc.ToString());
        }

        //RFID::exceptionHandler();
    }
    }

 

对应的XRMServicesInterface的C#代码库:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web.Services.Protocols;

namespace XRMServicesInterface
{
    using CrmSDK;
    public class XrmSdk
    {
        #region Constants
        /// <summary>
        /// User Domain
        /// </summary>
        private const string UserDomain = "cliffcrm";

        /// <summary>
        /// User Name
        /// </summary>
        private const string UserName = "administrator";

        /// <summary>
        /// Password
        /// </summary>
        private const string UserPassword = "Password";

         /// <summary>
        /// URL for the Organization Service
        /// </summary>
        private const string ServiceUrl = "https://sha-crm-cliff:5555/mscrmservices/2007/crmservice.asmx";

        #endregion

        static void Main(string[] args)
        {
          
            XrmSdk sdk = new XrmSdk();
            sdk.RetrieveCRMAccount();
        }

        public BusinessEntityCollection RetrieveCRMAccount()
        {

            CrmService crmService = new CrmService();
            // Set up the CRM Service.
            CrmAuthenticationToken token = new CrmAuthenticationToken();
            // You can use enums.cs from the SDK\Helpers folder to get the enumeration for Active Directory authentication.
            token.AuthenticationType = 0;
            token.OrganizationName = "CRM2011RTW";

            crmService.Url = ServiceUrl;
            crmService.UseDefaultCredentials = false;
            crmService.CrmAuthenticationTokenValue = token;
            crmService.Credentials = new NetworkCredential(UserName, UserPassword, UserDomain);
            crmService.Proxy = null;
            crmService.PreAuthenticate = true;
            try
            {

                // Create the column set that indicates the fields to be retrieved.
                ColumnSet cols = new ColumnSet();

                // Set the properties of the column set.
                cols.Attributes = new string[] { "name", "accountcategorycode", "accountclassificationcode", "accountid", "accountnumber",
                                     "aging60",  "creditlimit",  "revenue", "createdon", "owninguser", "parentaccountid",
                                     "transactioncurrencyid", "createdby", "donotemail", "statecode", "numberofemployees" };

                // Create the ConditionExpression.
                ConditionExpression condition = new ConditionExpression();

                // Set the condition for the retrieval to be when the city in the account's address is Sammamish.
                condition.AttributeName = "address1_city";
                condition.Operator = ConditionOperator.Like;
                condition.Values = new string[] { "Redmond" };

                // Create the FilterExpression.
                FilterExpression filter = new FilterExpression();

                // Set the properties of the filter.
                filter.FilterOperator = LogicalOperator.And;
                filter.Conditions = new ConditionExpression[] { condition };

                // Create the QueryExpression object.
                QueryExpression query = new QueryExpression();

                // Set the properties of the QueryExpression object.
                query.EntityName = EntityName.account.ToString();
                query.ColumnSet = cols;
                query.Criteria = filter;

               //  Query passed to service proxy.

                BusinessEntityCollection retrieved = crmService.RetrieveMultiple(query);

                 return retrieved;

            }
            catch (Exception ge)
            {
                throw ge;
            }
        }

    }
}

 

thanks

Clifford