Thursday, June 11, 2015

MS CRM performance improvement with metadata caching when creating SDK connection.


I was dealing with performance issues in WCF services which was using Microsoft Dynamic CRM SDK for basic CRUD operations.

Approach 1 – Never make your OrganizationServiceProxy as Static

I created a class variable of OrganizationProxy as static and every time the request come it is shared between multiple requests as that the property of a Static variable.


private static OrganizationServiceProxy _serviceProxy;
public static OrganizationServiceProxy OrganizationServiceProxy
{
    get
    {
        if (_serviceProxy == null)
        {
            string crmUrl = ConfigurationManager.AppSettings["crmUrl"];

            ClientCredentials creds = new ClientCredentials();
            creds.Windows.ClientCredential = new System.Net.NetworkCredential(
            ConfigurationManager.AppSettings["Username"],
            ConfigurationManager.AppSettings["password"],
            ConfigurationManager.AppSettings["Domain"]);

            _serviceProxy = new OrganizationServiceProxy(new Uri(crmUrl), null, creds, null);
            _serviceProxy.EnableProxyTypes();                   
        }
        return _serviceProxy;
    }
}


Definitely above solution resulted in enormous performance improvement.
But it also resulted in poisoning of OrganizationProxy and CRM Connection. I would like to explain poisoning of proxy with below diagram. 

An Ideal and expected scenario is whoever is creating an opportunity, CREATEDBY and OWNER field in CRM should be populated under his/her name as a Sales representative.


But what had happened, when WCF service was hit by multiple and parallel requests it has used the existing Organization Proxy to create an opportunity in CRM with some other user credentials.

Here Opportunity C and D are getting created under Rose instead D should be created under – Manager. (Probably that’s why he is angry :P)

Now, how to improve performance and to deal with the underline poisoning problem.
Solution-2: Make only Metadata Static and used in while creating OrganizationServiceProxy.

[ThreadStatic]
private static IServiceManagement<IOrganizationService> _ManagementService;
//Next step is to define the get method for this variable
public static OrganizationServiceProxy ManagementService
{
    get
    {
        string crmUrl = ConfigurationManager.AppSettings["crmUrl"];
        if (_ManagementService == null)
        {
            // Here we are creating Connection with only Metadata information about CRM,
            // which is quite heavy when making CRM Connections.
            IServiceManagement<IOrganizationService> ManagementServiceLocal =
                ServiceConfigurationFactory.CreateManagement(new Uri(crmUrl)); 
                // Observe NO Credentials being passed.
            _ManagementService = ManagementServiceLocal;
        }
        ClientCredentials creds = new ClientCredentials();
        creds.Windows.ClientCredential = new System.Net.NetworkCredential(
        ConfigurationManager.AppSettings["Username"],
        ConfigurationManager.AppSettings["password"],
        ConfigurationManager.AppSettings["Domain"]);

        // Here we are combining Management Instance and User Credentails
        // to create the Organization Proxy for doing CRUD Operation in CRM.
        OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(_ManagementService, creds);  
        serviceProxy.EnableProxyTypes();
        return serviceProxy;
    }
}


The OrganizationServiceProxy has an overloaded constructor method which can accept metadata as in parameter when creating organization proxy.

So we can cache Management Instance only which help us gaining performance and next we can always create  a fresh Organization Proxy with user credentials passing cached management service instance and this would avoid any poisoning of service Proxy.

Try this solution in your environment and let me know if it work and how much performance you gain.

Happy CRMing.

No comments: