I’ve already written a few posts about the CrmConnection class and how easy it is to use. While it’s a pretty simple object to work with, I’m surprised at how much interest there seems to be in it. Other than the name of a chronic pain in my a55, the terms CrmConnection and OrganizationService are the two most commonly searched and referred terms to this blog. Recently, I’ve been responsible for developer training for Dynamics CRM 2011 and started things off with showing people how to connect and use both the CrmConnection and IOrganizationService. To really drive the point home, I decided to use Telerik’s wonderful Just Decompile to disassemble the Microsoft.Xrm.Client.dll and the Microsoft.Xrm.Sdk.dll to show the inner workings of how many of the commonly used classes are built. With that in mind, let’s take a look under the hood at the CrmConnection object.
After loading the Microsoft.Xrm.Client.dll into Just Decompile, you’ll be presented with each of the classes available in the Microsoft.Xrm.Client namespace. Drilling down into the CrmConnection, you should see something roughly approximating this:
So
So nothing too shocking here right. After all, we know the CrmConnection is just a wrapper, syntactical sugar as they sometimes refer to such things, for the items you need to authenticate to OrganizationService. You see the ClientCredentials property which should come as no surprise, the DeviceCredentials property which should come as no surprise if you’ve connected to Crm Online and the ServiceUri. You see the default constructor as well as each of the overloaded constructors, including one which takes a connectionString name and one that takes an actual connectionStringSettings item. Drilling down into the overload that takes in the connectionString name, you see the following definition:
public CrmConnection(string connectionStringName) : this(CrmConnection.GetConnectionStringSettings(connectionStringName)) { }
That leads one to naturally wonder what GetConnectionStringSettings looks like right?
private static ConnectionStringSettings GetConnectionStringSettings(string connectionStringName) { ConnectionStringSettings item = ConfigurationManager.ConnectionStrings[connectionStringName]; if (item != null) { return item; } else { object[] objArray = new object[1]; objArray[0] = connectionStringName; throw new ConfigurationErrorsException("Unable to find a connection string with the name '{0}'.".FormatWith(objArray)); } }
Nothing too surprising there, right? If you’re like me, you’re wondering where all the parsing happens. I mean, where do things like the DeviceId and DeviceCredentials get parsed out of the connectionString so they can be used in the call to the OrganizationService? One natural guess might be to take a look at the CrmConnection.Parse method (even though we don’t see an explicit call, you tend to think it’s being called somewhere along the lines). CrmConnection.Parse is particular unremarkable:
public static CrmConnection Parse(string connectionString) { return new CrmConnection(connectionString.ToDictionary()); }
Now is where things get a little interesting. Remember the public constructors? There was a default constructor which had no parameters, there was one that took in a string parameter (corresponding to the connectionString name) and one that took in a parameter of connectionStringSettings. None of them took in a Dictionary. Well, none of the public constructors do anyway. If you look carefully at the Just Compile output, you’ll see two other private constructors present. The first of them takes in a generic Dictionary. The second one basically takes in every other thing under the sun.
Looking at the constructor employing the Dictionary, things start to get very clear very quickly:
private CrmConnection(IDictionary<string, string> connection) { string[] strArrays = new string[4]; strArrays[0] = "ServiceUri"; strArrays[1] = "Service Uri"; strArrays[2] = "Url"; strArrays[3] = "Server"; string[] strArrays1 = new string[2]; strArrays1[0] = "HomeRealmUri"; strArrays1[1] = "Home Realm Uri"; string[] strArrays2 = new string[1]; strArrays2[0] = "Domain"; string[] strArrays3 = new string[4]; strArrays3[0] = "UserName"; strArrays3[1] = "User Name"; strArrays3[2] = "UserId"; strArrays3[3] = "User Id"; string[] strArrays4 = new string[1]; strArrays4[0] = "Password"; string[] strArrays5 = new string[4]; strArrays5[0] = "DeviceId"; strArrays5[1] = "Device Id"; strArrays5[2] = "DeviceUserName"; strArrays5[3] = "Device User Name"; string[] strArrays6 = new string[2]; strArrays6[0] = "DevicePassword"; strArrays6[1] = "Device Password"; string[] strArrays7 = new string[1]; strArrays7[0] = "Timeout"; string[] strArrays8 = new string[2]; strArrays8[0] = "ProxyTypesEnabled"; strArrays8[1] = "Proxy Types Enabled"; string[] strArrays9 = new string[2]; strArrays9[0] = "ProxyTypesAssembly"; strArrays9[1] = "Proxy Types Assembly"; string[] strArrays10 = new string[2]; strArrays10[0] = "CallerId"; strArrays10[1] = "Caller Id"; string[] strArrays11 = new string[2]; strArrays11[0] = "ServiceConfigurationInstanceMode"; strArrays11[1] = "Service Configuration Instance Mode"; string[] strArrays12 = new string[2]; strArrays12[0] = "UserTokenExpiryWindow"; strArrays12[1] = "User Token Expiry Window"; this(connection.FirstNotNullOrEmpty<string>(strArrays), connection.FirstNotNullOrEmpty<string>(strArrays1), connection.FirstNotNullOrEmpty<string>(strArrays2), connection.FirstNotNullOrEmpty<string>(strArrays3), connection.FirstNotNullOrEmpty<string>(strArrays4), connection.FirstNotNullOrEmpty<string>(strArrays5), connection.FirstNotNullOrEmpty<string>(strArrays6), connection.FirstNotNullOrEmpty<string>(strArrays7), connection.FirstNotNullOrEmpty<string>(strArrays8), connection.FirstNotNullOrEmpty<string>(strArrays9), connection.FirstNotNullOrEmpty<string>(strArrays10), connection.FirstNotNullOrEmpty<string>(strArrays11), connection.FirstNotNullOrEmpty<string>(strArrays12)); }
You might have to read the code a time or two before it makes sense, but what you see is basically a placeholder for each of the values that comprise a CrmConnection ConnectionString and a means by which you can pass in a literal name or a friendly name and still get to the same place. The second ‘everything under the sun ‘ constructor is much more, well, what I would have expected to see. Why? Because as you look through it, it looks pretty much exactly like the code we used to connect to the CrmService with did before we had the luxury of using the CrmConnecti0n. Admittedly it’s rather long, but if you look at it carefully, it makes perfect sense and is quite easy to follow:
private CrmConnection(string serviceUri, string homeRealmUri, string domain, string userName, string password, string deviceId, string devicePassword, string timeout, string proxyTypesEnabled, string proxyTypesAssembly, string callerId, string serviceConfigurationInstanceMode, string userTokenExpiryWindow) { bool flag; object uri; object obj; TimeSpan? nullable; TimeSpan? nullable1; object obj1; ServiceConfigurationInstanceMode @enum; CrmConnection crmConnection = this; if (!string.IsNullOrWhiteSpace(serviceUri)) { uri = new Uri(serviceUri); } else { uri = null; } crmConnection.ServiceUri = (Uri)uri; CrmConnection crmConnection1 = this; if (!string.IsNullOrWhiteSpace(homeRealmUri)) { obj = new Uri(homeRealmUri); } else { obj = null; } crmConnection1.HomeRealmUri = (Uri)obj; if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(password)) { if (!string.IsNullOrWhiteSpace(userName) || !string.IsNullOrWhiteSpace(password)) { throw new ConfigurationErrorsException("The specified user credentials are invalid."); } } else { ClientCredentials clientCredential = new ClientCredentials(); if (string.IsNullOrWhiteSpace(domain)) { clientCredential.UserName.UserName = userName; clientCredential.UserName.Password = password; } else { clientCredential.Windows.ClientCredential = new NetworkCredential(userName, password, domain); } this.ClientCredentials = clientCredential; } if (string.IsNullOrWhiteSpace(deviceId) || string.IsNullOrWhiteSpace(devicePassword)) { if (!string.IsNullOrWhiteSpace(deviceId) || !string.IsNullOrWhiteSpace(devicePassword)) { throw new ConfigurationErrorsException("The specified device credentials are invalid."); } } else { ClientCredentials clientCredential1 = new ClientCredentials(); clientCredential1.UserName.UserName = deviceId; clientCredential1.UserName.Password = devicePassword; this.DeviceCredentials = clientCredential1; } CrmConnection crmConnection2 = this; if (!string.IsNullOrWhiteSpace(timeout)) { nullable = new TimeSpan?(TimeSpan.Parse(timeout)); } else { TimeSpan? nullable2 = null; nullable = nullable2; } crmConnection2.Timeout = nullable; CrmConnection crmConnection3 = this; if (!string.IsNullOrWhiteSpace(userTokenExpiryWindow)) { nullable1 = new TimeSpan?(TimeSpan.Parse(userTokenExpiryWindow)); } else { TimeSpan? nullable3 = null; nullable1 = nullable3; } crmConnection3.UserTokenExpiryWindow = nullable1; if (!bool.TryParse(proxyTypesEnabled, ref flag)) { flag = CrmConnection._defaultProxyTypesEnabled; } this.ProxyTypesEnabled = flag; CrmConnection crmConnection4 = this; if (!string.IsNullOrWhiteSpace(proxyTypesAssembly)) { obj1 = Assembly.Load(proxyTypesAssembly); } else { obj1 = null; } crmConnection4.ProxyTypesAssembly = (Assembly)obj1; if (!string.IsNullOrWhiteSpace(callerId)) { this.CallerId = new Guid?(new Guid(callerId)); } CrmConnection crmConnection5 = this; if (!string.IsNullOrWhiteSpace(serviceConfigurationInstanceMode)) { @enum = serviceConfigurationInstanceMode.ToEnum<ServiceConfigurationInstanceMode>(); } else { @enum = CrmConnection._defaultServiceConfigurationInstanceMode; } crmConnection5.ServiceConfigurationInstanceMode = @enum; }
So yes, this may be a little anti-climactic, after all what we ultimately showed is pretty much what you’d expect to see in the first place. But there are a few takeaways I’d pay attention to. First, it shows that with a little thought, you can abstract away a lot of code which becomes essentially unnecessary. Comparing the one line it takes to instantiate a CrmConnection with the multiple lines it takes to get to the same place without it, it’s clear that one approach will be a lot easier for people to learn, understand, use and maintain.
The other takeaway is with respect to building your own Microsoft Dynamics CRM 2011 development libraries. Although I haven’t actually tried to confirm it, I’ve heard from many people that the CrmConnection concept, as well as the OrganizationServiceContext (and the whole Entity Framework style approach to CRM development) were both created by the very talented folks at AdxStudio. Their product was so compelling that Microsoft either purchased or licensed it from AdxStudio so they could include it in the CRM 2011 SDK. (While I certainly don’t advocate rumor mongering, I’m pretty sure this rumor is true and since it’s a pretty flattering rumor in any case, I figured it’d be ok to mention, at least until I can confirm it). In any case, with a little thought and empathy for the developer, Shan and the guys at AdxStudio took something that was inelegant and generally considered a pain in the butt, and made it absolutely painless. I’m willing to bet that there are quite a few other brilliant and convenient ideas out there just waiting to be implemented by someone who’s frustrated by doing the same thing over and over. Think about using the same philosophy coupled with Extension methods. Do you think there’s some elegancy and simplicity possible if you coupled those two ideas together? B/c the CRM API has been maturing so quickly, a lot of things have yet to catch up – tooling being one clear example. There’s still a lot that’s quite cumbersome and error prone to write. Such things cause endless delays on CRM deployments and frustrate new CRM developers to no end.
I bet if you were to dig around the SDK libraries using Just Decompile (or your disassembler of choice) you’d find quite a few other interesting tidbits and probably at least a handful of opportunities to greatly simplify your future CRM 2011 development. Sure, Microsoft gave us several useful classes in their SDK, but no one says those have to be the ones you use. There’s nothing stopping you from creating YourCompany.Xrm.Client.dll or the YourCompany.Xrm.Client namespace. And if you have some ideas but don’t have the time to implement them, please feel free to post them below or write me privately – I can’t promise you I’ll have time to create them, but I’ll seriously consider anything sent my way and if time permits, I’ll be glad to take a stab at implementation and share the credit – heck this might be a good time to start a CodePlex project with just such a goal in mind.
Leave any questions in the Comments section, or write us: devteam@dynamics4.com
————————————————————–
KeyWords: CrmConnection, Microsoft.Xrm.Client.CrmConnection, CrmConnection Class, Microsoft.Xrm.Sdk.Entity,Microsoft Dynamics CRM 2011, Crm 2011, Dynamics CRM 2011, CrmConnection.Parse, Crm 2011 CrmConnection, OrganizationService, OrganizationServiceContext, Just Decompile, AdxStudio, CodePlex, Microsoft.Xrm.Client.dll, Microsoft.Xrm.Sdk.dll, Dynamics4, Dynamics4.com
I’m install MS Dynamics CRM 4.0 Arabic Language Pack, but i can’t see any deerneft, do you can tell me what’s change after installed Arabic Language Pack.thanks
Do you know if we can encrypt the connection string using the same mechansism for normal connectionStrings? What about using Enterprise library
This post is worth everyone’s attention. Where can I find out more on CrmConnection, CrmConnection 2011, AssignRequest, PublishAllXmlRequest
Interesting read. Ms Dynamics® CRM is surely an easy-to-use relationship-management technique that will adds to the output involving sales. Thank you for the discussion on CrmConnection and QueryExpression in C#. VB.NET would be nice too.
everything but how to use CrmConnection with CrmOnline and the Device Tool.
I’m impressed, I need to say. You leave nothing unknown about the new CrmConnection. A cynic might think you overdiscussed to pimp Search Engine rankings but that’s between you and Google and Bing and Yahoo.