我们遇到无法实例化CrmServiceClient
类的情况,由于构造函数内部深处出现“对象引用未设置为对象” 错误。我还收到了一个收藏集已被修改的信息;在某些情况下,枚举操作可能不会执行错误。
这并非一直发生,但是当我们很快触发多个请求时,我们似乎能够重现它。
我们如下创建对象:
var ctx = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
连接字符串有效,并且我们已将 RequireNewInstance 设置为true
我们最初在using块中使用ctx
,但被告知我们不应该处置CrmServiceClient,因此我们删除了using块,但这不能解决问题。 / p>
下面是堆栈跟踪-我只粘贴了相关部分。至此为止的堆栈可以是任何尝试连接到CRM来检索数据的代码
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at Microsoft.Xrm.Tooling.Connector.Utilities.GetOrgnameAndOnlineRegionFromServiceUri(Uri serviceUri, String& onlineRegion, String& organizationName, Boolean& isOnPrem)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.SetOrgnameAndOnlineRegion(Uri serviceUri)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(String serviceUri, String userName, String password, String domain, String homeRealmUri, String authType, String requireNewInstance, String clientId, String redirectUri, String tokenCacheStorePath, String loginPrompt, String certStoreName, String certThumbprint, String skipDiscovery)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(IDictionary`2 connection)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.Parse(String connectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.ConnectToCrmWebService(String crmConnectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient..ctor(String crmConnectionString)
答案 0 :(得分:2)
我相信我已经找到了问题所在。我使用DotNetPeek查看失败的基础代码。发生错误的位置是静态方法GetOrgnameAndOnlineRegionFromServiceUri
。
我跟踪到一个静态列表(discoSvcs
),该静态列表在方法返回之前被设置为null。其他调用此方法的线程也正在尝试使用此列表执行操作。最终,出现了一种竞争条件,一个线程可以检查该线程是否不为空。
我现在可以解决的唯一方法是通过使用锁确保在任何时候仅实例化一个 CrmServiceClient 。这不是很理想,但我已经没时间了
静态列表定义
namespace Microsoft.Xrm.Tooling.Connector
{
public class Utilities
{
private static CrmOnlineDiscoveryServers discoSvcs;
private static List<string> _autoRetryRetrieveEntityList;
private Utilities()
{
}
问题功能
在此函数的开头检查静态列表变量,如果该变量为null,则将填充一些值。然后在方法中稍后使用它,然后在finally
块中将其设置为null。
public static void GetOrgnameAndOnlineRegionFromServiceUri(
Uri serviceUri,
out string onlineRegion,
out string organizationName,
out bool isOnPrem)
{
isOnPrem = false;
onlineRegion = string.Empty;
organizationName = string.Empty;
if (serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS.COM") || serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.DE") || (serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.US") || serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS-INT.COM")))
{
if (Utilities.discoSvcs == null)
Utilities.discoSvcs = new CrmOnlineDiscoveryServers();
try
{
List<string> stringList = new List<string>((IEnumerable<string>) serviceUri.Host.Split(new string[1]
{
"."
}, StringSplitOptions.RemoveEmptyEntries));
organizationName = stringList[0];
stringList.RemoveAt(0);
StringBuilder stringBuilder = new StringBuilder();
foreach (string str in stringList)
{
if (!str.Equals("api"))
stringBuilder.AppendFormat("{0}.", (object) str);
}
string crmKey = stringBuilder.ToString().TrimEnd('.').TrimEnd('/');
stringBuilder.Clear();
if (!string.IsNullOrEmpty(crmKey))
{
CrmOnlineDiscoveryServer onlineDiscoveryServer = Utilities.discoSvcs.OSDPServers.Where<CrmOnlineDiscoveryServer>((Func<CrmOnlineDiscoveryServer, bool>) (w =>
{
if (w.DiscoveryServer != (Uri) null)
return w.DiscoveryServer.Host.Contains(crmKey);
return false;
})).FirstOrDefault<CrmOnlineDiscoveryServer>();
if (onlineDiscoveryServer != null && !string.IsNullOrEmpty(onlineDiscoveryServer.ShortName))
onlineRegion = onlineDiscoveryServer.ShortName;
}
isOnPrem = false;
}
finally
{
Utilities.discoSvcs.Dispose();
Utilities.discoSvcs = (CrmOnlineDiscoveryServers) null;
}
}
else
{
isOnPrem = true;
if (((IEnumerable<string>) serviceUri.Segments).Count<string>() < 2)
return;
organizationName = serviceUri.Segments[1].TrimEnd('/');
}
}