Dynamic CRM Connection

Standard

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.