关注本人微信和易信公众号: 微软动态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中使用组织服务的话,一般都是每次查询会建立一次连接,代码类似如下:
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.ServiceModel;
using System.Threading; namespace LuoYongLab
{
class Program
{
static void Main(string[] args)
{
try
{
for (var i = ; i < ; i++)
{
ThreadStart tStart = new ThreadStart(Work);
Thread thread = new Thread(tStart);
thread.Start();
}
Console.WriteLine("程序运行完成!");
Console.ReadKey();
}
catch (FaultException ex)
{
Console.WriteLine("程序出现异常:ex.Message=" + ex.Message);
Console.ReadKey();
}
} static void Work()
{
Console.WriteLine("线程开始" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
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);
Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";Token过期时间:" + crmSvc.OrganizationServiceProxy.SecurityTokenResponse.Response.Lifetime.Expires);
if (crmSvc.IsReady)
{
QueryExpression qe = new QueryExpression("organization");
qe.ColumnSet = new ColumnSet("languagecode", "basecurrencyid");
EntityCollection ec = crmSvc.RetrieveMultiple(qe);
if (ec.Entities.Count >= )
{
Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";组织偏好语言:" + ec.Entities[].GetAttributeValue<int>("languagecode"));
}
}
Console.WriteLine("线程结束" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
}
}
}
效果如下,可以看到大概需要7秒钟。
我用fiddler抓包,你会发现每次认证都会下载元数据,一共下载了5次。
如果我改动代码如下,类 ManagedTokenOrganizationServiceProxy 代码来自Ali Sharifi 的文章 REFRESH SECURITY TOKEN FOR MICROSOFT DYNAMICS CRM CONNECTION ,但是我发现没什么用,因为 this._proxy.SecurityTokenResponse == null,所以我这里不会使用。
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Configuration;
using System.ServiceModel;
using System.Threading; namespace ConsoleApp
{
class Program
{
public static IServiceManagement<IOrganizationService> sm;
public static AuthenticationCredentials authCredentials;
static void Main(string[] args)
{
sm = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ConfigurationManager.AppSettings["orgUrl"]));
authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["userName"];
authCredentials.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["passWord"];
authCredentials = sm.Authenticate(authCredentials);
try
{
for (var i = ; i < ; i++)
{
ThreadStart tStart = new ThreadStart(Work);
Thread thread = new Thread(tStart);
thread.Start();
}
Console.WriteLine("程序运行完成!");
Console.ReadKey();
}
catch (FaultException ex)
{
Console.WriteLine("程序出现异常:ex.Message=" + ex.Message);
Console.ReadKey();
}
} static void Work()
{
Console.WriteLine("线程开始" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(sm, authCredentials.ClientCredentials);
//OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(sm, authCredentials.SecurityTokenResponse);
//ManagedTokenOrganizationServiceProxy orgSvc = new ManagedTokenOrganizationServiceProxy(sm, authCredentials.ClientCredentials);
QueryExpression qe = new QueryExpression("organization");
qe.ColumnSet = new ColumnSet("languagecode", "basecurrencyid");
EntityCollection ec = orgSvc.RetrieveMultiple(qe);
if (ec.Entities.Count >= )
{
Console.WriteLine("线程ID: " + Thread.CurrentThread.ManagedThreadId + ";组织偏好语言:" + ec.Entities[].GetAttributeValue<int>("languagecode"));
}
Console.WriteLine("线程结束" + DateTime.Now.ToLongTimeString() + ";线程ID:" + Thread.CurrentThread.ManagedThreadId);
}
}
}
 
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System;
using System.ServiceModel;
using System.ServiceModel.Description; namespace ConsoleApp
{ public sealed class ManagedTokenOrganizationServiceProxy : OrganizationServiceProxy
{
private AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService> _proxyManager; public ManagedTokenOrganizationServiceProxy(Uri serviceUri, ClientCredentials userCredentials)
: base(serviceUri, null, userCredentials, null)
{
this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
} public ManagedTokenOrganizationServiceProxy(IServiceManagement<IOrganizationService> serviceManagement,
SecurityTokenResponse securityTokenRes)
: base(serviceManagement, securityTokenRes)
{
this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
} public ManagedTokenOrganizationServiceProxy(IServiceManagement<IOrganizationService> serviceManagement,
ClientCredentials userCredentials)
: base(serviceManagement, userCredentials)
{
this._proxyManager = new AutoRefreshSecurityToken<OrganizationServiceProxy, IOrganizationService>(this);
} protected override void AuthenticateCore()
{
this._proxyManager.PrepareCredentials();
base.AuthenticateCore();
} protected override void ValidateAuthentication()
{
this._proxyManager.RenewTokenIfRequired();
base.ValidateAuthentication();
}
} ///<summary>
/// Class that wraps acquiring the security token for a service
/// </summary> public sealed class AutoRefreshSecurityToken<TProxy, TService>
where TProxy : ServiceProxy<TService>
where TService : class
{
private TProxy _proxy; ///<summary>
/// Instantiates an instance of the proxy class
/// </summary> /// <param name="proxy">Proxy that will be used to authenticate the user</param>
public AutoRefreshSecurityToken(TProxy proxy)
{
if (null == proxy)
{
throw new ArgumentNullException("proxy");
} this._proxy = proxy;
} ///<summary>
/// Prepares authentication before authenticated
/// </summary> public void PrepareCredentials()
{
if (null == this._proxy.ClientCredentials)
{
return;
} switch (this._proxy.ServiceConfiguration.AuthenticationType)
{
case AuthenticationProviderType.ActiveDirectory:
this._proxy.ClientCredentials.UserName.UserName = null;
this._proxy.ClientCredentials.UserName.Password = null;
break;
case AuthenticationProviderType.Federation:
case AuthenticationProviderType.LiveId:
this._proxy.ClientCredentials.Windows.ClientCredential = null;
break;
default:
return;
}
} ///<summary>
/// Renews the token (if it is near expiration or has expired)
/// </summary> public void RenewTokenIfRequired()
{
if (null != this._proxy.SecurityTokenResponse &&
DateTime.UtcNow.AddMinutes() >= this._proxy.SecurityTokenResponse.Response.Lifetime.Expires)
{
try
{
this._proxy.Authenticate();
}
catch (CommunicationException)
{
if (null == this._proxy.SecurityTokenResponse ||
DateTime.UtcNow >= this._proxy.SecurityTokenResponse.Response.Lifetime.Expires)
{
throw;
}
}
}
}
}
}
我们可以看到执行时间也会缩短,从之前的大概需要7秒降低到需要1秒,速度提升不少。
 
我们看看Fiddler抓包效果,仅仅只有一次下载元数据,而且因为缓存执行的非常快。
 
如果要缓存的话,我这里在Application Start事件时候缓存代码如下,当然要添加对 System.Runtime.Caching 的引用。
using System.Runtime.Caching;            
ObjectCache cache = MemoryCache.Default;
CacheItemPolicy policy = new CacheItemPolicy();
policy.Priority = CacheItemPriority.NotRemovable;
IServiceManagement<IOrganizationService> sm = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ConfigurationManager.AppSettings["orgUrl"]));
cache.Set("sm", sm, policy);
AuthenticationCredentials authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["userName"];
authCredentials.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["passWord"];
cache.Set("authCredentials", sm.Authenticate(authCredentials), policy);

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

using System.Runtime.Caching;
ObjectCache cache = MemoryCache.Default;
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. Android OpenGL ES 开发(七): OpenGL ES 响应触摸事件

    像旋转三角形一样,通过预设程序来让对象移动对于吸引注意是很有用的,但是如果你想让你的OpenGL图形有用户交互呢?让你的OpenGL ES应用有触摸交互的关键是,扩展你的GLSurfaceView的实 ...

  2. [Swift]LeetCode475. 供暖器 | Heaters

    Winter is coming! Your first job during the contest is to design a standard heater with fixed warm r ...

  3. [Swift]LeetCode826. 安排工作以达到最大收益 | Most Profit Assigning Work

    We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the profit of the ith ...

  4. 小伙子,你真的搞懂 transient 关键字了吗?

    先解释下什么是序列化 我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术. Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将 ...

  5. IdentityServer Topics(7)- 注销

    注销IdentityServer与删除身份cookie一样简单,但是我们必须考虑将用户从客户端应用程序(甚至可能是上游身份提供程序)中注销. 一.删除身份认证Cookie 要删除身证认证cookie, ...

  6. C#版(打败99.28%的提交) - Leetcode 347. Top K Frequent Elements - 题解

    版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...

  7. 玩转C线性表和单向链表之Linux双向链表优化

    前言: 这次介绍基本数据结构的线性表和链表,并用C语言进行编写:建议最开始学数据结构时,用C语言:像栈和队列都可以用这两种数据结构来实现. 一.线性表基本介绍 1 概念: 线性表也就是关系户中最简单的 ...

  8. Chapter 4 Invitations——28

    "Oh, thanks, now that's all cleared up." Heavy sarcasm. “哦,真感谢,现在一切都清楚了.” 我很讽刺的说道 I realiz ...

  9. ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

      ServletRequest 基本概念 JavaWeb中的 "Request"对象  实际为   HttpServletRequest  或者  ServletRequest, ...

  10. tcpdump工具使用说明

    tcpdump采用命令行方式对接口的数据包进行筛选抓取,其丰富特性表现在灵活的表达式上. 注意,tcpdump只能抓取流经本机的数据包,不带任何选项的tcpdump,默认会抓取第一个网络接口,且只有将 ...