在Web应用程序中连接到CRM的最佳实践

时间:2017-09-29 20:05:53

标签: asp.net-mvc-5 connection httprequest dynamics-crm dynamics-crm-365

很抱歉,如果这个问题有点广泛,但如果这是关于普通的ASP.NET MVC 5基于Owin的应用程序与MSSQL服务器的默认连接的问题我不会有这么难,但我们使用CRM作为我们的数据库。

好的,我提到我正在研究ASP.NET MVC5应用程序,并且很难找到创建的最佳实践,保持打开并关闭与Dynamics CRM 365的连接?

我发现了很多帖子和博客,但每个人都拉着他的路走。

有人说,在using声明中打开新连接的每个请求都会更好,因此可以立即关闭(这听起来不错但是请求可能会很慢,因为在每个请求上都需要打开与CRM的新连接)。
有人说它'最好在应用程序范围内创建singleton对象,在应用程序生命周期内保持打开状态,并在每个请求上重复使用它。

通常我会在一些简单的控制台应用中使用OrganizationServiceProxy,但在这种情况下我不确定我应该使用OrganizationServiceProxy还是CrmServiceClient还是别的?

如果有人有或有类似的问题,任何提示都会很棒。

更新

@Nicknow

我从SDK 365下载了SDK并使用了这个dll-s。
Microsoft.Xrm.Sdk.dllMicrosoft.Crm.Sdk.Proxy.dllMicrosoft.Xrm.Tooling.Connector.dllMicrosoft.IdentityModel.Clients.ActiveDirectory.dll

你提到

  

Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5。

如果这个nuget包正确使用我下载的官方程序集,或者对这个程序包有一些修改?

关于该测试

  

证明测试

如果我做对了,无论我使用using语句,实现Dispose()方法还是仅仅在应用程序范围内使用静态类一辈子的应用程序我都会得到相同的实例(如果我使用默认设置RequireNewInstance=false)?

  

为了简化代码,我通常会创建一个静态类(也可以使用单例,但通常是矫枉过正)来返回CrmServiceClient对象。这样我的代码就不会出现新的CrmServiceClient调用,如果我想改变关于如何建立连接的话。

因此,在适用于应用程序生命周期的应用程序范围上创建静态类是一种好习惯吗?这意味着发出请求的每个用户都会使用相同的实例?对于那个连接,这不是我的性能问题吗?

  

所有的方法调用都将执行完成或抛出异常,因此即使GC需要一段时间没有打开的连接就会占用资源和/或阻止其他活动。

这个让我回到我总是获得CrmServiceClient的相同实例的部分,并获得了xrm.tooling处理缓存连接的部分,但另一方面却发生了什么(Web应用程序)。 不是与CRM(即CrmServiceClient)非托管资源的连接,不应该明确地Dispose()吗?

我在CrmServiceClient找到了一些示例,并且CrmServiceClient中的几乎所有示例都使用IOrganizationServiceCrmServiceClient.OrganizationWebProxyClientCrmServiceClient.OrganizationServiceProxy中投放。

为什么这样做有什么好处?

我收到了很多问题,但已经分配了这个问题,有没有可以指向我的在线文档?

1 个答案:

答案 0 :(得分:7)

首先,我假设您正在使用Nuget的最新SDK DLL:Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5。

我从来没有在using声明中包含连接,我也不认为我曾经见过这样做的例子。在我们有工具库之前,有一些来自旧时代的例子,其中创建OrganizationServiceProxy的调用被包装在using语句中,导致许多缺乏经验的开发人员发布具有连接性能问题的代码。

幸运的是,大部分内容已通过Xrm.Tooling库修复。

使用CrmServiceClient

创建连接对象

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

现在,如果我创建一个OrganizationServiceContext(或一个早期绑定的等价物)对象,我会将其包裹在using中,以便在我完成我的工作单元时确定处置它

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

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

Xrm.Tooling库为您提供连接通道和身份验证的所有其他功能。除非您指定每次创建新频道(通过向连接字符串添加' RequireNewInstance = true'或在调用useUniqueInstance时将true设置为new CrmServiceClient)库将重用现有的经过身份验证的通道。

我使用以下代码进行快速验证测试:

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...");
}

当我使用RequireNewInstance=true运行时,我得到以下控制台输出:

  • 获得客户#1的时间:2216
  • WhoAmI的时间#1:2394
  • 获得客户#2的时间:4603
  • WhoAmI的时间#2:4780

显然,创建每个连接的时间大致相同。

现在,如果我将其更改为RequireNewInstance=false(这是默认值),我会得到以下内容:

  • 获得客户#1的时间:3761
  • WhoAmI时间#1:3960
  • 获得客户#2的时间:3961
  • WhoAmI的时间#2:4145
哇,这是一个很大的不同。到底是怎么回事?在第二次调用时,Xrm.Tooling库使用现有的服务通道和身份验证(它缓存了它。)

您可以更进一步,将new CrmServiceClient调用包装在using中,并且您将获得相同的行为,因为丢弃返回实例并不会破坏缓存。 / p>

所以这将返回类似于上面的时间:

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}");
}

为了简化代码,我通常会创建一个静态类(也可以使用单例,但通常是矫枉过正)来返回CrmServiceClient对象。这样我的代码就不会被new CrmServiceClient调用弄乱,我是否想要改变关于如何建立连接的任何内容。

要从根本上回答有关using的问题,我们不需要使用它,因为没有任何内容可以发布。所有方法调用都将执行完成或抛出异常,因此即使GC需要一段时间没有开放连接,因此会占用资源和/或阻止其他活动。