A while ago I had to build a piece of software that connects to Dynamic CRM and retrieve values from an Entity to Export it to CSV file. Reading through existing code of other developers I noticed a lot of Impersonation taking place, or credentials being stored in the web.config/app.config file. I do not like this. I want my application to connect to CRM using my Active Directory credentials.
CRM is still a great big playpen to me where I feel and push the boundaries to see what it can do with it. Lacking experience with it allows me a lot of freedom to experiment.
After playing a bit and reading a lot on how to best avoid the whole credentials-in-the-config-file scenario, I came up with these classes.
This class build up an Organization Service Url for your favourite CRM Organization
using System; using System.Configuration; namespace MyApplication.CrmServices { internal class OrganizationServiceUrl { const string XrmServiceLocation = @"/XRMServices/2011/Organization.svc"; public OrganizationServiceUrl(string organizationUrl = null) { if (string.IsNullOrWhiteSpace(organizationUrl) && string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["CrmInstanceUrl"])) throw new InvalidOperationException("Organization URL is required."); organizationUrl = string.IsNullOrWhiteSpace(organizationUrl) ? ConfigurationManager.AppSettings["CrmInstanceUrl"] : organizationUrl ; if (string.IsNullOrWhiteSpace(organizationUrl)) throw new InvalidOperationException(@"The [URL] setting was not found in the <appSettings> section of the configuration file."); Uri = new Uri(string.Format("{0}{1}", organizationUrl.EndsWith("/") ? organizationUrl.Substring(0, organizationUrl.LastIndexOf("/") - 1) : organizationUrl, XrmServiceLocation)); } public Uri Uri { get; private set; } } }
Next up I created a class that will give me ClientCredentials from the Default NeworkCredentials and accepts the OrganizationServiceUrl as a parameter.
using System.ServiceModel.Description; using System.Net; namespace MyApplication.CrmServices { internal class CrmClientCredentials : ClientCredentials { private readonly OrganizationServiceUrl serviceUrl; public CrmClientCredentials(OrganizationServiceUrl serviceUrl) : base() { this.serviceUrl = serviceUrl; this.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials.GetCredential(serviceUrl.Uri, "Basic"); } } }
Finally, I can connect to the Organization service through the CRM SDK without having to store any credential in the config file.
using System; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Client; namespace MyApplication.CrmServices { public class Connector : IDisposable { private OrganizationServiceUrl organizationServiceUrl; private CrmClientCredentials crmClientCredentials; public bool disposed; public Connector() { organizationServiceUrl = new OrganizationServiceUrl(string.Empty); crmClientCredentials = new CrmClientCredentials(organizationServiceUrl); disposed = false; } public Connector(string organizationUrl) { organizationServiceUrl = new OrganizationServiceUrl(organizationUrl); crmClientCredentials = new CrmClientCredentials(organizationServiceUrl); disposed = false; } public IOrganizationService Proxy { get { return new OrganizationServiceProxy(organizationServiceUrl.Uri, null, crmClientCredentials, null); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { if (organizationServiceUrl != null) organizationServiceUrl = null; if (crmClientCredentials != null) crmClientCredentials = null; } disposed = true; } } } }
Whether this is the correct, or even acceptable, way of connecting to CRM I do not know. What I do know, is that thus far, it works for me. It is simple and reusable.