关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复256或者20170512可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me 。
 
最近做代码审查,有个建议是Improve Microsoft Dynamics CRM service channel allocation performance的建议,请教了微软专家,同事也参考了官方的文章:Best practices for developing with Dynamics 365 for Customer Engagement ,Get了一下新技能,下面我做一次传声筒和翻译器,请听我讲来。
为了更好的看到效果,我这里使用了多个线程来凸显效果。我以前的项目,不在Dynamics 365中使用组织服务的话,一般都是每次查询会建立一次连接,代码类似如下:
  1. using Microsoft.Xrm.Sdk;
  2. using Microsoft.Xrm.Sdk.Query;
  3. using Microsoft.Xrm.Tooling.Connector;
  4. using System;
  5. using System.ServiceModel;
  6. using System.Threading;
  7.  
  8. namespace LuoYongLab
  9. {
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. try
  15. {
  16. for (var i = ; i < ; i++)
  17. {
  18. ThreadStart tStart = new ThreadStart(Work);
  19. Thread thread = new Thread(tStart);
  20. thread.Start();
  21. }
  22. Console.WriteLine("程序运行完成!");
  23. Console.ReadKey();
  24. }
  25. catch (FaultException ex)
  26. {
  27. Console.WriteLine("程序出现异常:ex.Message=" + ex.Message);
  28. Console.ReadKey();
  29. }
  30. }
  31.  
  32. static void Work()
  33. {
  34. Console.WriteLine("线程开始" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
  35. var crmSvc = new CrmServiceClient(new System.Net.NetworkCredential("crmadmin@luoyong.me", "Pass", null), Microsoft.Xrm.Tooling.Connector.AuthenticationType.IFD, "demo.luoyong.me", "", "demo", useUniqueInstance: false, useSsl: true);
  36. Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";Token过期时间:" + crmSvc.OrganizationServiceProxy.SecurityTokenResponse.Response.Lifetime.Expires);
  37. if (crmSvc.IsReady)
  38. {
  39. QueryExpression qe = new QueryExpression("organization");
  40. qe.ColumnSet = new ColumnSet("languagecode", "basecurrencyid");
  41. EntityCollection ec = crmSvc.RetrieveMultiple(qe);
  42. if (ec.Entities.Count >= )
  43. {
  44. Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";组织偏好语言:" + ec.Entities[].GetAttributeValue<int>("languagecode"));
  45. }
  46. }
  47. Console.WriteLine("线程结束" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
  48. }
  49. }
  50. }
效果如下,可以看到大概需要7秒钟。
我用fiddler抓包,你会发现每次认证都会下载元数据,一共下载了5次。
如果我改动代码如下,类 ManagedTokenOrganizationServiceProxy 代码来自Ali Sharifi 的文章 REFRESH SECURITY TOKEN FOR MICROSOFT DYNAMICS CRM CONNECTION ,但是我发现没什么用,因为 this._proxy.SecurityTokenResponse == null,所以我这里不会使用。
  1. using Microsoft.Xrm.Sdk;
  2. using Microsoft.Xrm.Sdk.Client;
  3. using Microsoft.Xrm.Sdk.Query;
  4. using System;
  5. using System.Configuration;
  6. using System.ServiceModel;
  7. using System.Threading;
  8.  
  9. namespace ConsoleApp
  10. {
  11. class Program
  12. {
  13. public static IServiceManagement<IOrganizationService> sm;
  14. public static AuthenticationCredentials authCredentials;
  15. static void Main(string[] args)
  16. {
  17. sm = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ConfigurationManager.AppSettings["orgUrl"]));
  18. authCredentials = new AuthenticationCredentials();
  19. authCredentials.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["userName"];
  20. authCredentials.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["passWord"];
  21. authCredentials = sm.Authenticate(authCredentials);
  22. try
  23. {
  24. for (var i = ; i < ; i++)
  25. {
  26. ThreadStart tStart = new ThreadStart(Work);
  27. Thread thread = new Thread(tStart);
  28. thread.Start();
  29. }
  30. Console.WriteLine("程序运行完成!");
  31. Console.ReadKey();
  32. }
  33. catch (FaultException ex)
  34. {
  35. Console.WriteLine("程序出现异常:ex.Message=" + ex.Message);
  36. Console.ReadKey();
  37. }
  38. }
  39.  
  40. static void Work()
  41. {
  42. Console.WriteLine("线程开始" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
  43. OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(sm, authCredentials.ClientCredentials);
  44. //OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(sm, authCredentials.SecurityTokenResponse);
  45. //ManagedTokenOrganizationServiceProxy orgSvc = new ManagedTokenOrganizationServiceProxy(sm, authCredentials.ClientCredentials);
  46. QueryExpression qe = new QueryExpression("organization");
  47. qe.ColumnSet = new ColumnSet("languagecode", "basecurrencyid");
  48. EntityCollection ec = orgSvc.RetrieveMultiple(qe);
  49. if (ec.Entities.Count >= )
  50. {
  51. Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";组织偏好语言:" + ec.Entities[].GetAttributeValue<int>("languagecode"));
  52. }
  53. Console.WriteLine("线程结束" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
  54. }
  55. }
  56. }
 
  1. using Microsoft.Xrm.Sdk;
  2. using Microsoft.Xrm.Sdk.Client;
  3. using System;
  4. using System.ServiceModel;
  5. using System.ServiceModel.Description;
  6.  
  7. namespace ConsoleApp
  8. {
  9.  
  10. public sealed class ManagedTokenOrganizationServiceProxy : OrganizationServiceProxy
  11. {
  12. private AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService> _proxyManager;
  13.  
  14. public ManagedTokenOrganizationServiceProxy(Uri serviceUri, ClientCredentials userCredentials)
  15. : base(serviceUri, null, userCredentials, null)
  16. {
  17. this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
  18. }
  19.  
  20. public ManagedTokenOrganizationServiceProxy(IServiceManagement<IOrganizationService> serviceManagement,
  21. SecurityTokenResponse securityTokenRes)
  22. : base(serviceManagement, securityTokenRes)
  23. {
  24. this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
  25. }
  26.  
  27. public ManagedTokenOrganizationServiceProxy(IServiceManagement<IOrganizationService> serviceManagement,
  28. ClientCredentials userCredentials)
  29. : base(serviceManagement, userCredentials)
  30. {
  31. this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
  32. }
  33.  
  34. protected override void AuthenticateCore()
  35. {
  36. this._proxyManager.PrepareCredentials();
  37. base.AuthenticateCore();
  38. }
  39.  
  40. protected override void ValidateAuthentication()
  41. {
  42. this._proxyManager.RenewTokenIfRequired();
  43. base.ValidateAuthentication();
  44. }
  45. }
  46.  
  47. ///<summary>
  48. /// Class that wraps acquiring the security token for a service
  49. /// </summary>
  50.  
  51. public sealed class AutoRefreshSecurityToken<TProxy, TService>
  52. where TProxy : ServiceProxy<TService>
  53. where TService : class
  54. {
  55. private TProxy _proxy;
  56.  
  57. ///<summary>
  58. /// Instantiates an instance of the proxy class
  59. /// </summary>
  60.  
  61. /// <param name="proxy">Proxy that will be used to authenticate the user</param>
  62. public AutoRefreshSecurityToken(TProxy proxy)
  63. {
  64. if (null == proxy)
  65. {
  66. throw new ArgumentNullException("proxy");
  67. }
  68.  
  69. this._proxy = proxy;
  70. }
  71.  
  72. ///<summary>
  73. /// Prepares authentication before authenticated
  74. /// </summary>
  75.  
  76. public void PrepareCredentials()
  77. {
  78. if (null == this._proxy.ClientCredentials)
  79. {
  80. return;
  81. }
  82.  
  83. switch (this._proxy.ServiceConfiguration.AuthenticationType)
  84. {
  85. case AuthenticationProviderType.ActiveDirectory:
  86. this._proxy.ClientCredentials.UserName.UserName = null;
  87. this._proxy.ClientCredentials.UserName.Password = null;
  88. break;
  89. case AuthenticationProviderType.Federation:
  90. case AuthenticationProviderType.LiveId:
  91. this._proxy.ClientCredentials.Windows.ClientCredential = null;
  92. break;
  93. default:
  94. return;
  95. }
  96. }
  97.  
  98. ///<summary>
  99. /// Renews the token (if it is near expiration or has expired)
  100. /// </summary>
  101.  
  102. public void RenewTokenIfRequired()
  103. {
  104. if (null != this._proxy.SecurityTokenResponse &&
  105. DateTime.UtcNow.AddMinutes() >= this._proxy.SecurityTokenResponse.Response.Lifetime.Expires)
  106. {
  107. try
  108. {
  109. this._proxy.Authenticate();
  110. }
  111. catch (CommunicationException)
  112. {
  113. if (null == this._proxy.SecurityTokenResponse ||
  114. DateTime.UtcNow >= this._proxy.SecurityTokenResponse.Response.Lifetime.Expires)
  115. {
  116. throw;
  117. }
  118. }
  119. }
  120. }
  121. }
  122. }
我们可以看到执行时间也会缩短,从之前的大概需要7秒降低到需要1秒,速度提升不少。
 
我们看看Fiddler抓包效果,仅仅只有一次下载元数据,而且因为缓存执行的非常快。
 
如果要缓存的话,我这里在Application Start事件时候缓存代码如下,当然要添加对 System.Runtime.Caching 的引用。
  1. using System.Runtime.Caching;
    ObjectCache cache = MemoryCache.Default;
  2. CacheItemPolicy policy = new CacheItemPolicy();
  3. policy.Priority = CacheItemPriority.NotRemovable;
  4. IServiceManagement<IOrganizationService> sm = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ConfigurationManager.AppSettings["orgUrl"]));
  5. cache.Set("sm", sm, policy);
  6. AuthenticationCredentials authCredentials = new AuthenticationCredentials();
  7. authCredentials.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["userName"];
  8. authCredentials.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["passWord"];
  9. cache.Set("authCredentials", sm.Authenticate(authCredentials), policy);

然后在代码中获取组织服务就用如下代码:

  1. using System.Runtime.Caching;
    ObjectCache cache = MemoryCache.Default;
  2. OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(((IServiceManagement<IOrganizationService>)cache["sm"]), ((AuthenticationCredentials)cache["authCredentials"]).ClientCredentials);
 

一种提升连接Dynamics 365性能的方法的更多相关文章

  1. JS中三种字符串连接方式及其性能比较

    工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方法,这里将它们一一列出顺便也对它们的性能做个具体的比较. 第一种方法  用连接符“+”把要连接的字符串连起来 ...

  2. JavaScript中三种字符串连接方式及其性能比较

    参考地址: https://www.cnblogs.com/programs/p/5554742.html 工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方 ...

  3. T4 模板 : 一种提升ASP.NET MVC开发速度方法

    最近由于需要在框架中提供一些自定义模板的功能,找到了一篇博客,可惜似乎是翻译工具直接翻的,读不通顺,就试着自己翻译下,我不会完全翻译原文的句子,可能会对原文进行小范围的我认为更合适的句子并添加些注释, ...

  4. Dynamics 365应用程序池回收对连接造成的影响。

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  5. Dynamics 365 CRM 开发架构简介

    Dynamics 365 CRM提供了多种编程模型,你可以灵活地按需选用最佳模式. 本文是对Dynamics 365 CRM编程模型的综述. 概览 下图表明了Dynamics 365 CRM的主要可编 ...

  6. Spring下配置几种常用连接池

    1.连接池概述 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是 ...

  7. 启用WCF压缩提升Dynamics 365 CE的网络性能

    摘要: 微软动态CRM专家罗勇 ,回复307或者20190308可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 本文系根据微 ...

  8. Android4种网络连接方式HttpClient、HttpURLConnection、OKHttp和Volley优缺点和性能对比

    比较的指标: 1.cpu 2.流量 3.电量 4.内存占用 5.联网时间 功能点: 1.重试机制 2.提供的扩展功能 3.易用性 4.是否https 5.是否支持reflect api,OkHttp有 ...

  9. 升级本地部署的CRM到Dynamics 365及部分新特性介绍。

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复241或者20161226可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

随机推荐

  1. 【安富莱专题教程第3期】开发板搭建Web服务器,利用花生壳让电脑和手机可以外网远程监控

    说明:1.  开发板Web服务器的设计可以看我们之前发布的史诗级网络教程:链接.2.  需要复杂些的Web设计模板,可以使用我们V6开发板发布的综合Demo:链接.3.  教程中使用的是花生壳免费版, ...

  2. [Swift]LeetCode280. 摆动排序 $ Wiggle Sort

    Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] < ...

  3. [Swift]LeetCode636. 函数的独占时间 | Exclusive Time of Functions

    Given the running logs of n functions that are executed in a nonpreemptive single threaded CPU, find ...

  4. [Swift]LeetCode910. 最小差值 II | Smallest Range II

    Given an array A of integers, for each integer A[i] we need to choose either x = -K or x = K, and ad ...

  5. java中this和super关键字的使用

    这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ...

  6. Hecher学生互助平台(团队项目第一次)

    团队项目作业链接:https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2978 一.团队简介 团队名称:Suc ...

  7. Mac下 .bash_profile 和 .zshrc 两者之间的区别

    这是我碰到的需要 source 之后才能使用环境变量的问题,我就不细究了,说说我的看法. .bash_profile 中修改环境变量只对当前窗口有效,而且需要 source ~/.bash_profi ...

  8. Git的使用--如何将本地项目上传到Github(三种简单、方便的方法)

    一.第一种方法: 1.首先你需要一个github账号,所以还没有的话先去注册吧! https://github.com/ 我们使用git需要先安装git工具,这里给出下载地址,下载后一路(傻瓜式安装) ...

  9. I-think-3

    一段很有哲理的话,与大家分享一下: 时光匆匆, 有些东西很重要,有些东西不重要, 有些东西已经不再重要,有些东西还是很重要. 宏观地看待人生,大学文凭只是一种达到目标的途径,而并非是唯一. 主要坚定自 ...

  10. 图像识别基本算法之SURF

    图像识别.人脸识别可行的算法有很多.但是作为学习,如果能理清这个问题研究的历程及其主线,会对你深入理解当前研究最新的发展有很多帮助.本文是自己在学习过程中的笔记,大多内容来自于网络,出处请参考最后的引 ...