MS CRM 万能连接
SDK中有一个例子叫” Sample: Simplified Connection Quick Start using Microsoft Dynamics CRM 2011 and Microsoft Dynamics CRM Online”。这个例子演示了如何连接 CRM On-premises, CRM On-premises IFD, 以及 CRM Online。我觉得还不够简化,下面我演示一个更简化的版本,而且我们只执行一个WhoAmIRequest的请求,和一个Retrieve的请求。
在看代码之前,我首先发现了sdk的例子中有一个问题,在配置文件中,对于CRM Online和CRM IFD的connection string,URL的部分单单写出server name是不够的,应该写Organization Service的URL。
首先看配置文件,在配制文件中我们使用connection string,它配置起来很简单,而且最大的好处是还可以加密。
<?xml version="1.0"?><configuration> <connectionStrings> <!-- Online using Office 365 --> <!-- <add name="Server=CRM Online, organization=contoso, user=someone" connectionString="Url=https://contoso.crm.dynamics.com; Username=someone@contoso.onmicrosoft.com; Password=password;"/> --> <!-- Online using Windows Live ID --> <!-- <add name="Server=CRM Online, organization=contoso, user=someone@hotmail.com" connectionString="Url=https://rmibv.api.crm4.dynamics.com/XRMServices/2011/Organization.svc; Username=someone@hotmail.com; Password=password; DeviceID=11hfn41bbqrg580vyvoea05abc; DevicePassword=fuqNIlx%e$.l*+ax_#8O4abc;"/>--> <!--On-premises with provided user credentials--> <!--<add name="Server=nlbesawse21, organization=vdl, user=administrator" connectionString="Url=http://myserver/AdventureWorksCycle; Domain=domainName; Username=userName; Password=password;"/>--> <!-- On-premises using Windows integrated security --> <!--<add name="Server=myserver, organization=AdventureWorksCycle" connectionString="Url=http://myserver/AdventureWorksCycle;"/>--> <!-- On-Premises (IFD) with claims --> <!--<add name="Server=litware.com, organization=contoso, user=someone@litware.com" connectionString="Url=https://abc.abc.com/XRMServices/2011/Organization.svc; Username=someone@litware.com; Password=password;"/>--> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup></configuration>
以下是连接程序的代码,连接不同的CRM只需要更改配置文件,不需要更改任何代码
using System;using System.Collections.Generic;using Microsoft.Xrm.Client.Services;using Microsoft.Xrm.Client;using Microsoft.Crm.Sdk.Messages;using System.ServiceModel;using System.Configuration;using Microsoft.Xrm.Sdk;using Microsoft.Xrm.Sdk.Query;namespace SimpleConnection{ public class SimplifiedConnection { #region Class Level Members private Guid _accountId; private OrganizationService _orgService; #endregion Class Level Members public void Run(String connectionString, bool promptforDelete) { try { // Establish a connection to the organization web service using CrmConnection. Microsoft.Xrm.Client.CrmConnection connection = CrmConnection.Parse(connectionString); // Obtain an organization service proxy. // The using statement assures that the service proxy will be properly disposed. using (_orgService = new OrganizationService(connection)) { // Obtain information about the logged on user from the web service. Guid userid = ((WhoAmIResponse)_orgService.Execute(new WhoAmIRequest())).UserId; Entity systemUser = _orgService.Retrieve("systemuser", userid, new ColumnSet(new string[] { "firstname", "lastname" })); Console.WriteLine("Logged on user is {0} {1}.", systemUser["firstname"].ToString(), systemUser["lastname"].ToString()); } } // Catch any service fault exceptions that Microsoft Dynamics CRM throws. catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>) { // You can handle an exception here or pass it back to the calling method. throw; } } #region Public Methods #endregion Public Methods #region Private Methods /// <summary> /// Gets web service connection information from the app.config file. /// If there is more than one available, the user is prompted to select /// the desired connection configuration by name. /// </summary> /// <returns>A string containing web service connection configuration information.</returns> private static String GetServiceConfiguration() { // Get available connection strings from app.config. int count = ConfigurationManager.ConnectionStrings.Count; // Create a filter list of connection strings so that we have a list of valid // connection strings for Microsoft Dynamics CRM only. List<KeyValuePair<String, String>> filteredConnectionStrings = new List<KeyValuePair<String, String>>(); for (int a = 0; a < count; a++) { if (isValidConnectionString(ConfigurationManager.ConnectionStrings[a].ConnectionString)) filteredConnectionStrings.Add (new KeyValuePair<string, string> (ConfigurationManager.ConnectionStrings[a].Name, ConfigurationManager.ConnectionStrings[a].ConnectionString)); } // No valid connections strings found. Write out and error message. if (filteredConnectionStrings.Count == 0) { Console.WriteLine("An app.config file containing at least one valid Microsoft Dynamics CRM " + "connection string configuration must exist in the run-time folder."); Console.WriteLine("\nThere are several commented out example connection strings in " + "the provided app.config file. Uncomment one of them and modify the string according " + "to your Microsoft Dynamics CRM installation. Then re-run the sample."); return null; } // If one valid connection string is found, use that. if (filteredConnectionStrings.Count == 1) { return filteredConnectionStrings[0].Value; } // If more than one valid connection string is found, let the user decide which to use. if (filteredConnectionStrings.Count > 1) { Console.WriteLine("The following connections are available:"); Console.WriteLine("------------------------------------------------"); for (int i = 0; i < filteredConnectionStrings.Count; i++) { Console.Write("\n({0}) {1}\t", i + 1, filteredConnectionStrings[i].Key); } Console.WriteLine(); Console.Write("\nType the number of the connection to use (1-{0}) [{0}] : ", filteredConnectionStrings.Count); String input = Console.ReadLine(); int configNumber; if (input == String.Empty) input = filteredConnectionStrings.Count.ToString(); if (!Int32.TryParse(input, out configNumber) || configNumber > count || configNumber == 0) { Console.WriteLine("Option not valid."); return null; } return filteredConnectionStrings[configNumber - 1].Value; } return null; } /// <summary> /// Verifies if a connection string is valid for Microsoft Dynamics CRM. /// </summary> /// <returns>True for a valid string, otherwise False.</returns> private static Boolean isValidConnectionString(String connectionString) { // At a minimum, a connection string must contain one of these arguments. if (connectionString.Contains("Url=") || connectionString.Contains("Server=") || connectionString.Contains("ServiceUri=")) return true; return false; } #endregion Private Methods #region Main method /// <summary> /// Standard Main() method used by most SDK samples. /// </summary> /// <param name="args"></param> static public void Main(string[] args) { try { // Obtain connection configuration information for the Microsoft Dynamics // CRM organization web service. String connectionString = GetServiceConfiguration(); if (connectionString != null) { SimplifiedConnection app = new SimplifiedConnection(); app.Run(connectionString, true); } } catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp); Console.WriteLine("Code: {0}", ex.Detail.ErrorCode); Console.WriteLine("Message: {0}", ex.Detail.Message); Console.WriteLine("Trace: {0}", ex.Detail.TraceText); Console.WriteLine("Inner Fault: {0}", null == ex.Detail.InnerFault ? "Has Inner Fault" : "No Inner Fault"); } catch (System.TimeoutException ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine("Message: {0}", ex.Message); Console.WriteLine("Stack Trace: {0}", ex.StackTrace); Console.WriteLine("Inner Fault: {0}", null == ex.InnerException.Message ? "Has Inner Fault" : "No Inner Fault"); } catch (System.Exception ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine(ex.Message); // Display the details of the inner exception. if (ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>; if (fe != null) { Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp); Console.WriteLine("Code: {0}", fe.Detail.ErrorCode); Console.WriteLine("Message: {0}", fe.Detail.Message); Console.WriteLine("Trace: {0}", fe.Detail.TraceText); Console.WriteLine("Inner Fault: {0}", null == fe.Detail.InnerFault ? "Has Inner Fault" : "No Inner Fault"); } } } // Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException, // SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException. finally { Console.WriteLine("Press <Enter> to exit."); Console.ReadLine(); } } #endregion Main method }}
最后再说一下,连接CRM Online的时候,需要DeviceID和DevicePassword。很多人不懂DeviceID是干什么用的。DeviceID的目的就是注册一个设备,使这个设备可以使用Windows Live ID。当你注册了这个设备后,任何用户就都可以使用这个设备了。所以如果这个是一个从未注册过的设备,你首先要注册它。关于如何注册一个设备,可以使用sdk带的deviceregistration工具。具体的命令是DeviceRegistration.exe /operation:Register。命令运行成功后,你就可以拷贝生成的Device ID和Device Password了。