无法实例化 CrmServiceClient

CrmServiceClient cannot be instantiated

我们遇到了 CrmServiceClient class 无法实例化的情况,'Object reference not set to an object' 错误来自于构造函数。我还收到了 Collection was modified;枚举操作在某些情况下可能无法执行错误。

这不会一直发生,但我们似乎能够在我们非常快速地触发多个请求时重现它。

我们创建对象如下:

 var ctx = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);

连接字符串有效,我们已将 RequireNewInstance 设置为 true

我们最初在 using 块中使用 ctx,但我们被告知不应处理 CrmServiceClient,因此我们删除了 using 块,但这并没有解决问题.

下面是堆栈跟踪 - 我只粘贴了相关部分。导致这一点的堆栈可以是任何试图连接到 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)

我相信我已经找到问题所在。我使用 DotNetPeek 查看失败的底层代码。静态方法 GetOrgnameAndOnlineRegionFromServiceUri 是发生错误的地方。

我追踪到一个静态列表 (discoSvcs),该列表在方法 returns 之前被设置为 null。调用这个方法的其他线程也在尝试用这个列表做事。结果是存在一种竞争条件,其中一个线程可以检查它是否不为空。

我现在能绕过它的唯一方法是确保在任何时候都只有一个 CrmServiceClient 被实例化,方法是使用锁。这并不理想,但我 运行 没时间了

静态列表定义

namespace Microsoft.Xrm.Tooling.Connector
{
  public class Utilities
  {
    private static CrmOnlineDiscoveryServers discoSvcs;
    private static List<string> _autoRetryRetrieveEntityList;

    private Utilities()
    {
    }

问题函数

在此函数的开头检查静态列表变量,如果它为空,则用一些值填充它。然后在 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('/');
      }
    }