asp.net-mvc-5 - 在 Web 应用程序中连接到 CRM 的最佳实践

标签 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在一些简单的控制台应用程序中,但在这种情况下我不确定我是否应该使用 OrganizationServiceProxyCrmServiceClient或者是其他东西?

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

更新:

@尼克诺

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

你提到

Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.



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

关于那个测试

proof test



如果我做对了,不管我是否使用 using声明,实现Dispose()方法或仅在应用程序范围内使用静态类以获得应用程序的生命周期我将始终获得相同的实例(如果我使用默认设置 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.



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

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类型转换于 IOrganizationService使用 CrmServiceClient.OrganizationWebProxyClientCrmServiceClient.OrganizationServiceProxy .

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

我有很多问题,但这已经被分配问了,是否有任何在线文档可以指点我?

最佳答案

首先,我假设您使用的是 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 (或早期绑定(bind)的等价物)对象我确实将其包装在 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 库为您处理连接 channel 和身份验证等所有其他事情。除非您每次都指定创建一个新 channel (通过在连接字符串中添加 'RequireNewInstance=true' 或在调用 useUniqueInstance 时将 true 设置为 new CrmServiceClient),否则库将重用现有的已验证 channel 。

我使用以下代码进行了快速验证测试:
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
  • 我是谁的时间#1:2394
  • 获得客户 #2 的时间:4603
  • 我是谁的时间#2:4780

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

    现在,如果我将其更改为 RequireNewInstance=false (这是默认设置)我得到以下信息:
  • 获得客户 #1 的时间:3761
  • 我是谁的时间#1:3960
  • 获得客户 #2 的时间:3961
  • 我是谁的时间#2:4145

  • 哇,这是一个很大的不同。到底是怎么回事?在第二次调用时,Xrm.Tooling 库使用现有的服务 channel 和身份验证(它已缓存。)

    您可以更进一步,将您的 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 需要一段时间,也没有打开的连接在那里占用资源和/或阻止其他事件。

    关于asp.net-mvc-5 - 在 Web 应用程序中连接到 CRM 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46496210/

    相关文章:

    c# - 服务器的图像文件路径不是 C : drive MVC5

    python - Django/Python 如何获取完整的请求头?

    javascript - 如何保持 C# 和 Javascript 代码同步?

    c# - 检查 Mysql DB 的用户名和密码 C#

    c# - TCP 连接阶段失败(从 JAVA 客户端调用 Web 服务到 C# 服务器)

    mysql - Visual Studio 中 MySQL 的连接字符串

    java.lang.IllegalArgumentException : Illegal character in path at index 33: https://box. one.th/app/api/上传

    java - 将变量从 JSP 传递到 servlet

    c# - Controller 从 ASP.NET MVC5 表单接收空值

    c# - 如何使用 StructureMap (4.0) 将依赖项注入(inject)自定义属性? MVC5项目