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