在 Web 应用程序中连接到 CRM 的最佳实践
Best practice for connections to CRM in web application
很抱歉,如果这个问题有点宽泛,但如果这是关于正常的问题 ASP.NET 基于 MVC 5 Owin 的应用程序,默认连接到 MSSQL 服务器,我不会有这么困难的时间,但我们使用 CRM作为我们的数据库。
好的,正如我提到的,我正在开发 ASP.NET MVC5 应用程序,并且很难找到创建、保持打开和关闭与 Dynamics CRM 365 连接的最佳实践?
我找到了很多帖子和博客,但每个人都在自己的路边停车。
有人说在 using
语句中打开新连接的每个请求更好,这样它就可以立即关闭(这听起来不错,但请求可能会很慢,因为在每个请求上它都需要打开与 CRM 的新连接).
有人说最好在应用程序范围内创建 singleton
对象,在应用程序生命周期中保持打开状态并在每个请求中重用它。
通常我会在一些简单的控制台应用程序中使用 OrganizationServiceProxy
但在这种情况下我不确定我应该使用 OrganizationServiceProxy
还是 CrmServiceClient
或其他什么?
如果有人有类似的问题,任何提示都会很好。
更新:
@尼克诺
我从 SDK 365 下载了 SDK 并正在使用这个 dll-s。
Microsoft.Xrm.Sdk.dll
、Microsoft.Crm.Sdk.Proxy.dll
、Microsoft.Xrm.Tooling.Connector.dll
和 Microsoft.IdentityModel.Clients.ActiveDirectory.dll
.
你提到
Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
如果这个 nuget 包使用我下载的官方程序集是正确的,或者这个包有一些修改?
关于那个测试
proof test
如果我做对了,无论我是使用 using
语句,实现 Dispose()
方法,还是只在应用程序范围内使用静态 class 应用程序的整个生命周期,我都会一直获取相同的实例(如果我使用默认设置 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.
因此,在应用程序生命周期内的应用程序范围内创建静态 class 是一种很好的做法吗?这意味着每个发出请求的用户都将使用相同的实例?那不会是那个连接的性能问题吗?
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.
这让我回到我总是获得 CrmServiceClient
的相同实例并获得 xrm.tooling 处理另一端缓存连接的部分,但在这一端发生了什么(Web 应用程序).
与 CRM(即 CrmServiceClient
)的连接不是非托管资源吗,我不应该 Dispose()
明确吗?
我找到了一些使用 CrmServiceClient
的示例,几乎所有示例中 CrmServiceClient
都是使用 CrmServiceClient.OrganizationWebProxyClient
或 CrmServiceClient.OrganizationServiceProxy
转换为 IOrganizationService
。
为什么会这样?这样做有什么好处?
我有很多问题,但已经有很多问题了,是否有任何在线文档可以指点我?
首先,我假设您使用的是来自 Nuget 的最新 SDK DLL:Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
我从来没有将连接包装在 using
语句中,而且我认为我从未见过这样做的示例。有来自 "old days" 的示例,在我们有工具库之前,其中对创建 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' 添加到连接字符串或在调用 new CrmServiceClient
时将 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
中,您将获得相同的行为,因为处理 return 实例不会破坏缓存。
所以这将 return 次与上面类似:
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}");
}
为了代码简单,我通常创建一个静态 class(也可以使用单例,但通常会过大)到 return 一个 CrmServiceClient
对象。这样一来,我的代码就不会充斥着 new CrmServiceClient
调用,如果我想更改有关连接方式的任何内容。
从根本上回答关于using
的问题,我们不需要使用它,因为没有什么可以发布的。您的所有方法调用都将执行完成或抛出异常,因此即使 GC 需要一段时间,也没有打开的连接在那里占用资源 and/or 阻塞其他 activity。
很抱歉,如果这个问题有点宽泛,但如果这是关于正常的问题 ASP.NET 基于 MVC 5 Owin 的应用程序,默认连接到 MSSQL 服务器,我不会有这么困难的时间,但我们使用 CRM作为我们的数据库。
好的,正如我提到的,我正在开发 ASP.NET MVC5 应用程序,并且很难找到创建、保持打开和关闭与 Dynamics CRM 365 连接的最佳实践?
我找到了很多帖子和博客,但每个人都在自己的路边停车。
有人说在 using
语句中打开新连接的每个请求更好,这样它就可以立即关闭(这听起来不错,但请求可能会很慢,因为在每个请求上它都需要打开与 CRM 的新连接).
有人说最好在应用程序范围内创建 singleton
对象,在应用程序生命周期中保持打开状态并在每个请求中重用它。
通常我会在一些简单的控制台应用程序中使用 OrganizationServiceProxy
但在这种情况下我不确定我应该使用 OrganizationServiceProxy
还是 CrmServiceClient
或其他什么?
如果有人有类似的问题,任何提示都会很好。
更新:
@尼克诺
我从 SDK 365 下载了 SDK 并正在使用这个 dll-s。
Microsoft.Xrm.Sdk.dll
、Microsoft.Crm.Sdk.Proxy.dll
、Microsoft.Xrm.Tooling.Connector.dll
和 Microsoft.IdentityModel.Clients.ActiveDirectory.dll
.
你提到
Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
如果这个 nuget 包使用我下载的官方程序集是正确的,或者这个包有一些修改?
关于那个测试
proof test
如果我做对了,无论我是使用 using
语句,实现 Dispose()
方法,还是只在应用程序范围内使用静态 class 应用程序的整个生命周期,我都会一直获取相同的实例(如果我使用默认设置 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.
因此,在应用程序生命周期内的应用程序范围内创建静态 class 是一种很好的做法吗?这意味着每个发出请求的用户都将使用相同的实例?那不会是那个连接的性能问题吗?
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.
这让我回到我总是获得 CrmServiceClient
的相同实例并获得 xrm.tooling 处理另一端缓存连接的部分,但在这一端发生了什么(Web 应用程序).
与 CRM(即 CrmServiceClient
)的连接不是非托管资源吗,我不应该 Dispose()
明确吗?
我找到了一些使用 CrmServiceClient
的示例,几乎所有示例中 CrmServiceClient
都是使用 CrmServiceClient.OrganizationWebProxyClient
或 CrmServiceClient.OrganizationServiceProxy
转换为 IOrganizationService
。
为什么会这样?这样做有什么好处?
我有很多问题,但已经有很多问题了,是否有任何在线文档可以指点我?
首先,我假设您使用的是来自 Nuget 的最新 SDK DLL:Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
我从来没有将连接包装在 using
语句中,而且我认为我从未见过这样做的示例。有来自 "old days" 的示例,在我们有工具库之前,其中对创建 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' 添加到连接字符串或在调用 new CrmServiceClient
时将 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
中,您将获得相同的行为,因为处理 return 实例不会破坏缓存。
所以这将 return 次与上面类似:
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}");
}
为了代码简单,我通常创建一个静态 class(也可以使用单例,但通常会过大)到 return 一个 CrmServiceClient
对象。这样一来,我的代码就不会充斥着 new CrmServiceClient
调用,如果我想更改有关连接方式的任何内容。
从根本上回答关于using
的问题,我们不需要使用它,因为没有什么可以发布的。您的所有方法调用都将执行完成或抛出异常,因此即使 GC 需要一段时间,也没有打开的连接在那里占用资源 and/or 阻塞其他 activity。