0
votes

We are in the process of migrating from Dynamics on-prem to Dynamics 365 online. So we had to change also a webapp that is connecting to Dynamics.

The webapp is still working but the performance is poor. We started to do some traces to see why. In this trace we saw that the app is doing for a single request different calls to Dynamics online. Reason for this is that we are indeed retrieving different sets of data. But we are surprised to see that authentication is done also multiple times. This authentication is slowing down the response from dynamics. We were expecting that authentication was done only with the first request.

The code I'm using to make the connection is in an abstract class that is instantiated by different other classes. This classes are using the following property returning a CrmServiceClient from the namespace Microsoft.Xrm.Tooling.Connector:

     protected CrmServiceClient CustomCrmServiceProxy
    {
        get
        {
            CrmServiceClient client = new CrmServiceClient(CrmConnection.Connectionstring);
            client.CallerId = GetCallerId();

            return client;
        }
    }

The connectionstring is AuthType=ClientSecret;url={0};ClientId={1};ClientSecret={2}; with the values replaced.

In the classes using the abstract class we are calling the property like

var data = this.CustomCrmServiceProxy.RetrieveMultiple("fetch xml");

Important is that we are passing the callerid to the CrmServiceClient and this one can be different when the visitor switch to a page in another language.

Is there a way to prevent the multiple authentication? Is implementing a singleton pattern an option? But what with the different callerids in that case? And is there maybe a good example for CrmServiceClient?

3

3 Answers

0
votes

Can you try something like this?

This would create a single instance of the connection (with the callerID) and then just continually refer to that instance.

CrmServiceClient _client = null;

protected CrmServiceClient CustomCrmServiceProxy
{
  get
  {
    if (_client == null)
    {
        _client = new CrmServiceClient(CrmConnection.Connectionstring);
        _client.CallerId = GetCallerId();
    }
    return _client;
}
0
votes

The CrmServiceClient offers a number of constructors giving the opportunity to reuse a connection instance.

E.g. the following constructor overload has parameter useUniqueInstance. Pass a false value to it when a cached instance should be used.

public CrmServiceClient(string userId, SecureString password, string domain, string homeRealm, string hostName, string port, string orgName, bool useUniqueInstance = false, bool useSsl = false, OrganizationDetail orgDetail = null)

In most cases however a web app will be consumed by multiple clients, often concurrently, and a singleton connection object would not scale well in those scenarios. In these cases you can introduce a connection pool.

A connection pool class would be responsible for maintaining a collection of CrmServiceClient instances. A factory pattern could be used to claim instances from the pool object. When disposed, the factory instance returns all claimed instances to the pool.

Your factory class could implement the existing IOrganizationServiceFactory. This interface is designed with impersonation requirements in mind.

Note: do not make classes that currently use CrmServiceClient connections responsible for creating these instances. Instead inject IOrganizationServiceFactory or IOrganizationService objects into the constructors of these classes.

0
votes

I have seen situations where a program executes a get accessor more times than I think it should.

Rather than having it as a property, I'd say try making it a method.

protected CrmServiceClient GetService()
{
    var client = new CrmServiceClient(CrmConnection.Connectionstring);
    client.CallerId = GetCallerId();
    return client;
}

Then, one option for lazy instantiation would be:

private CrmServiceClient _svc;
private CrmServiceClient svc => _svc ?? (_svc = GetService());