Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for connections to CRM in web application

am sorry if this question will be a bit to broad but if this is question about normal ASP.NET MVC 5 Owin based application with default connection to MSSQL server i would not have such hard time but we use CRM as our database.

Ok as i mention am working on ASP.NET MVC5 application and am having hard time finding what is the best practice to create, keep open and to close connection to Dynamics CRM 365?

I found some many posts and blogs but everyone pulling on his side of the road.

Some say it's better for every request to open new connection in using statement so it could be closed right away (that's sounds good but it's a possible that requests will be slow because on every request it needs to open new connection to CRM).
Some say it' better to make singleton object on application scope, keep it open during application lifetime and reuse it on every request.

Normally i would use OrganizationServiceProxy in some simple console app but in this case am not sure should i use OrganizationServiceProxy or CrmServiceClient or something else?

If anyone have or had some similar problem, any hint would be great.

UPDATE:

@Nicknow

I downloaded SDK from SDK 365 and am using this dll-s.
Microsoft.Xrm.Sdk.dll, Microsoft.Crm.Sdk.Proxy.dll, Microsoft.Xrm.Tooling.Connector.dll and Microsoft.IdentityModel.Clients.ActiveDirectory.dll.

You mention

Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.

if am correct this nuget package use official assembly that i downloaded, or there are some modification to this package?

About that test

proof test

if i got it right, no matter if i use using statement, implement Dispose() method or just use static class on application scope for a lifetime of application i will allways get same instance (If i use default settings RequireNewInstance=false)?

For code simplicity, I usually create a static class (a singleton could be used too, but would usually be overkill) to return a CrmServiceClient object. That way my code is not littered with new CrmServiceClient calls should I want to change anything about how the connection is being made.

So it would be good practice to create static class on application scope that lives for application lifetime? That means that every user that makes request would use same instance ? Wouldn't that be i performance issue for that one connection?

All of your method calls will execute to completion or throw an exception thus even if the GC takes a while there is no open connection sitting out there eating up resources and/or blocking other activity.

This one takes me back to section where i allways get same instance of CrmServiceClient and got the part that xrm.tooling handles cached connection o the other side but what happens on this side (web application). Isn't the connection to CRM (i.e. CrmServiceClient) unmanaged resources, shouldn't i Dispose() it explicitly?

I found some examples with CrmServiceClient and pretty much in all examples CrmServiceClient is casted in IOrganizationService using CrmServiceClient.OrganizationWebProxyClient or CrmServiceClient.OrganizationServiceProxy.

Why is that and what are the benefits of that?

I got so many questions but this is already allot to ask, is there any online documentation that you could point me to it?

like image 245
Genato Avatar asked Jan 03 '23 09:01

Genato


1 Answers

First, I'm assuming you are using the latest SDK DLLs from Nuget: Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.

I never wrap the connection in a using statement and I don't think I've ever seen an example where that is done. There are examples from the "old days", before we had tooling library, where calls to create OrganizationServiceProxy were wrapped in a using statement, which caused a lot of inexperienced developers to release code with connection performance issues.

Luckily most of this has been fixed for us through the Xrm.Tooling library.

Create your connection object using CrmServiceClient:

CrmServiceClient crmSvc = new CrmServiceClient(@"...connection string goes here...");

Now if I create an OrganizationServiceContext (or an early-bound equivalent) object I do wrap that in a using so that it is determinedly disposed when I've completed my unit of work.

using (var ctx = new OrganizationServiceContext(crmSvc))
{
    var accounts = from a in ctx.CreateQuery("account")
                    select a["name"];

    Console.WriteLine(accounts.ToList().Count());
}

The Xrm.Tooling library handles everything else for you as far the connection channel and authentication. Unless you specify to create a new channel each time (by adding 'RequireNewInstance=true' to the connection string or setting the useUniqueInstance to true when calling new CrmServiceClient) the library will reuse the existing authenticated channel.

I used the following code to do a quick proof test:

void Main()
{

    var sw = new Stopwatch();
    sw.Start();

    var crmSvc = GetCrmClient();

    Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");

    crmSvc.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}"); 

    var crmSvc2 = GetCrmClient();

    Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");

    crmSvc2.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");    

}

public CrmServiceClient GetCrmClient()
{
    return new CrmServiceClient("...connection string goes here...");
}

When I run this with RequireNewInstance=true I get the following console output:

  • Time to get Client # 1: 2216
  • Time to WhoAmI # 1: 2394
  • Time to get Client # 2: 4603
  • Time to WhoAmI # 2: 4780

Clearly it was taking about the same amount of time to create each connection.

Now, if I change it to RequireNewInstance=false (which is the default) I get the following:

  • Time to get Client # 1: 3761
  • Time to WhoAmI # 1: 3960
  • Time to get Client # 2: 3961
  • Time to WhoAmI # 2: 4145

Wow, that's a big difference. What is going on? On the second call the Xrm.Tooling library uses the existing service channel and authentication (which it cached.)

You can take this one step further and wrap your new CrmServiceClient calls in a using and you'll get the same behavior, because disposing of the return instanced does not destroy the cache.

So this will return times similar to above:

using (var crmSvc = GetCrmClient())
{
    Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");

    crmSvc.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}");
}

using (var crmSvc2 = GetCrmClient())
{
    Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");

    crmSvc2.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");
}

For code simplicity, I usually create a static class (a singleton could be used too, but would usually be overkill) to return a CrmServiceClient object. That way my code is not littered with new CrmServiceClient calls should I want to change anything about how the connection is being made.

To fundamentally answer the question about using, we don't need to use it because there is nothing to be released. All of your method calls will execute to completion or throw an exception thus even if the GC takes a while there is no open connection sitting out there eating up resources and/or blocking other activity.

like image 150
Nicknow Avatar answered Feb 03 '23 07:02

Nicknow