【问题标题】:Best practice for connections to CRM in web application在 Web 应用程序中连接到 CRM 的最佳实践
【发布时间】:2017-09-29 20:05:53
【问题描述】:

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

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

我发现了很多帖子和博客,但每个人都在坚持自己的道路。

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

通常我会在一些简单的控制台应用程序中使用OrganizationServiceProxy,但在这种情况下我不确定我应该使用OrganizationServiceProxyCrmServiceClient 还是其他什么?

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

更新:

@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() 方法,或者只是在应用程序范围内使用静态类,我都会得到相同的实例(如果我使用默认设置@ 987654334@)?

为了代码简单,我通常创建一个静态类(也可以使用单例,但通常会过大)来返回一个 CrmServiceClient 对象。这样,如果我想更改有关如何建立连接的任何内容,我的代码就不会被新的 CrmServiceClient 调用乱扔。

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

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

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

我发现了一些带有CrmServiceClient 的示例,并且几乎所有示例中的CrmServiceClient 都使用CrmServiceClient.OrganizationWebProxyClientCrmServiceClient.OrganizationServiceProxy 转换为IOrganizationService

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

我有很多问题,但这已经分配给我了,有什么在线文档可以指点我吗?

【问题讨论】:

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


【解决方案1】:

首先,我假设您使用的是 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”添加到连接字符串或在调用true 时将useUniqueInstance 设置为true),否则库将重用现有的经过身份验证的通道。

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

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 中,您将获得相同的行为,因为处理返回实例不会破坏缓存。

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

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 需要一段时间,也没有打开的连接在那里占用资源和/或阻止其他活动。

【讨论】:

  • 您好,我用新问题更新了我的问题。 :)(评论是不够的)
  • 请使用代码示例针对您遇到的每个特定问题发布一个新问题。否则,它会造成混乱并且无法保持在 Stackoverflow 的预期使用范围内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
相关资源
最近更新 更多