【问题标题】:Updating to .net 4.6.2 from .net 4.5.2 causing Object Reference Exception on ExecuteCore method within xrm sdk从 .net 4.5.2 更新到 .net 4.6.2 导致 xrm sdk 中的 ExecuteCore 方法出现对象引用异常
【发布时间】:2017-07-06 00:15:23
【问题描述】:

我们有一个针对 .net 4.5.2 框架开发的 Win 8.1 商店应用程序,当计算机更新到 .net 4.6.2 时,我们会收到一个 Object Reference is not set to the value of an Object exception。

该应用程序由两部分组成,商店应用程序包含所有 UI 逻辑,代理程序包含与 Dynamics CRM Outlook 连接器的所有数据层交互。

在运行第一个 WhoAmI 请求时,我在 base.ExecuteCore(request) 上确定了出错的行。

有趣的是,如果代理以调试模式启动或在控制台应用程序中使用,则相同的代码可以工作。代理由我们的 UI 应用程序使用应用程序 URL 启动,并确认已启动。

我尝试了以下方法:

  • 将项目更新到 .net 4.6.2
  • 将相关的 nuget 包更新到最新版本,包括 xrm sdk dll。
  • 反编译 Xrm.SDK dll 并检查方法中使用的每个属性以查找错误位置,并找到所有要设置的相关属性。
  • 绕过 Outlook 连接器并直接访问 CRM 网络服务

我的想法是 .net 4.5.2 和 .net 4.6.2 以不同的方式执行代码会导致错误。

有人对如何解决这个问题有任何想法吗?

供参考:

CRM 版本: 8.0.1.90

堆栈跟踪

在 Microsoft.Xrm.Sdk.Client.OrganizationServiceContextInitializer.Initialize() 在 Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.ExecuteCore(组织请求请求) 在 c:\PGW.Mobility\PGW.Mobility.CrmProxy\CrmContextProvider.cs:line 127 中的 CrmProxy.CrmOrganizationProxy.ExecuteCore(OrganizationRequest request) 处

类:

using System;
using System.Collections.Concurrent;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.ServiceModel.Description;
using System.Threading;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using NLog;
using Mobility.Crm.Core;
using Mobility.CrmProxy.Interfaces;

namespace Mobility.CrmProxy
{
    public class CrmContextProvider : ICrmContextProvider
    {
        private readonly IEntityMapper _mapper;
        private readonly ICrmMetadataHolder _metadataHolder;
        private readonly OrganizationProxyPool _proxyPool;

        public CrmContextProvider(IEntityMapper mapper, ICrmMetadataHolder metadataHolder, OrganizationProxyPool proxyPool, ICrmConnectionConfig crmConnectionConfig)
        {
            _proxyPool = proxyPool;
            _mapper = mapper;
            _metadataHolder = metadataHolder;
        }

        public CrmProxyContext Context()
        {
            Contract.Ensures(Contract.Result<CrmProxyContext>() != null);
            var proxy = _proxyPool.Acquire();
            return new CrmProxyContext(_proxyPool, proxy, _mapper, _metadataHolder);
        }
    }

    public interface IOrganizationServiceReleaser
    {
        void Release(IOrganizationService proxy);
    }

    /// <summary>
    /// Pool of expensive organization proxies to improve overall performance
    /// </summary>
    public class OrganizationProxyPool : IOrganizationServiceReleaser
    {
        public static int OrgProxyInstanceCount = 0;

        private readonly Logger _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.FullName);
        private readonly ICrmConnectionConfig _crmConnectionConfig;

        private static readonly ConcurrentBag<IOrganizationService> OrgProxyPool = new ConcurrentBag<IOrganizationService>();

        public OrganizationProxyPool(ICrmConnectionConfig crmConnectionConfig)
        {
             _crmConnectionConfig = crmConnectionConfig;
        }

        public IOrganizationService Acquire()
        {
            IOrganizationService proxy;
            if (!OrgProxyPool.TryTake(out proxy))
            {
                var count = Interlocked.Increment(ref OrgProxyInstanceCount);
                _log.Info("Creating new OrganizationServiceProxy (total count: {0})", count);
                var crmProxy = new CrmOrganizationProxy(_crmConnectionConfig);
                // enable types declared in Crm.Core assembly
                //crmProxy.EnableProxyTypes(typeof(CrmContext).Assembly);   //Removed as per null reference exception with .net 4.6.2??
            crmProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior(Assembly.GetExecutingAssembly()));
                proxy = crmProxy;
            }
            return proxy;
        }

        public void Release(IOrganizationService proxy)
        {
            // ignore failed proxies
            var crmProxy = proxy as CrmOrganizationProxy;
            if (crmProxy != null && !crmProxy.Failed)
                OrgProxyPool.Add(proxy);
        }
    }

    class CrmOrganizationProxy : OrganizationServiceProxy
    {
        private readonly ICrmConnectionConfig _crmConnectionConfig;

        public CrmOrganizationProxy(ICrmConnectionConfig crmConnectionConfig)
            : base(
                new Uri(crmConnectionConfig.CurrentCrmServerUri), null,
                new ClientCredentials
                {
                    Windows = { ClientCredential = crmConnectionConfig.CurrentCredentials }
                },
                null)
        {
            _crmConnectionConfig = crmConnectionConfig;
        }

        public bool Failed { get; private set; }

        protected override void AuthenticateCore()
        {
            if (_crmConnectionConfig.IsOffline)
            {
                // TODO: report bug to XRM team
                // note: this is reflection workaround over bug in Xrm when connecting offline Outlook CRM
                // without this Xrm throws weird "authentication failed!" exception which is wrong because
                // Cassini web server (where offline CRM server hosted) doesn't even support any authentication

                var isAuthPrivateSetter = typeof(ServiceProxy<IOrganizationService>).
                    GetProperty("IsAuthenticated").GetSetMethod(true);
                var proxyBase = (ServiceProxy<IOrganizationService>)this;
                isAuthPrivateSetter.Invoke(proxyBase, new object[] { true });
            }
            else
            {
                base.AuthenticateCore();
            }
        }

        protected override OrganizationResponse ExecuteCore(OrganizationRequest request)
        {
            // Telerik decompiler shows that context ivokes only Execute() method of proxy, 
            // so it is enough to check failures only in ExecuteCore()
            try
            {
                return base.ExecuteCore(request);
            }
            catch (Exception)
            {
                Interlocked.Decrement(ref OrganizationProxyPool.OrgProxyInstanceCount);
                Failed = true;
                throw;
            }
        }
    }
}

2017 年 7 月 17 日更新

将代码更改为以下代码后,我现在遇到了更详细的错误。

错误:

LastCrmError = "无法登录 Dynamics CRMOrganizationServiceProxy 为空"

代码:

var crmProxy = new CrmServiceClient("Url=http://crm/AdventureWorks;");
crmProxy.GetMyCrmUserId();

添加基于文件的日志记录后,我现在得到一个有用的错误,我认为

OperationContext.Current 的值不是此 OperationContextScope 安装的 OperationContext 值。

堆栈跟踪:在 System.ServiceModel.OperationContextScope.PopContext() 在 Microsoft.Xrm.Sdk.Client.ServiceContextInitializer1.Dispose(布尔处理) 在 Microsoft.Xrm.Sdk.Client.ServiceContextInitializer1.Dispose() 在 Microsoft.Xrm.Sdk.Client.DiscoveryServiceProxy.Execute(DiscoveryRequest 请求) 在 Microsoft.Xrm.Tooling.Connector.CrmWebSvc.DiscoverOrganizations(Uri discoveryServiceUri,Uri homeRealmUri,ClientCredentials clientCredentials,ClientCredentials deviceCredentials)

【问题讨论】:

  • 根据文档OrganizationServiceProxy.ExecuteCore 仅供内部使用。你试过OrganizationServiceProxy.Execute吗?
  • 我删除了服务的自定义类,还是一样的错误,这是使用执行功能。
  • 我会在Dynamics Community询问
  • 您是否尝试过使用 Xrm Tooling 中的 CrmServiceClient 类?您连接到 CRM 的方式已弃用
  • 是的,试过了,仍然出现空引用异常,我尝试使用主机和组织服务代理进行实例化。

标签: c# .net wcf dynamics-crm


【解决方案1】:

也许尝试使用连接字符串实例化 CrmServiceClient。

这里是示例连接字符串...

CRM 2016 和 Dynamics 365 在线:

<add name="dev26" connectionString="Url=https://dev26.crm.dynamics.com; Username=user@dev26.onmicrosoft.com; Password=Pass; AuthType=Office365" />

具有集成安全性的本地部署:

<add name="prod" connectionString="Url=http://myserver/AdventureWorksCycle;"/>

带有凭据的本地部署:

<add name="prod" connectionString="Url=http://myserver/AdventureWorksCycle; Domain=mydomain; Username=administrator; Password=password; AuthType=AD;"/>

CRM 2016 之前的本地 IFD:

<add name="prod" connectionString="Url=https://contoso.litware.com; Username=someone@litware.com; Password=password; AuthType=IFD;"/>

适用于 CRM 2016 及更高版本 (v8.0+) 的本地 IFD

<add name="prod" connectionString="ServiceUri=https://contoso.litware.com/contoso; Domain=contoso; Username=contoso\administrator; Password=password; AuthType=IFD; LoginPrompt=Never;" />

【讨论】:

  • 我已经这样做了,有趣的是它得到了一个更详细的错误,我在上面添加了错误和代码。
  • 感谢您的更新。如果您单步执行代码,创建 crmProxy 后 crmProxy.IsReady 的值是多少?如果它是假的,也许尝试将 AuthType=AD 添加到连接字符串,如果这不起作用,请尝试添加凭据。
  • 不幸的是,仍然是同样的错误,与上面的 OperationContextScope 有关。
【解决方案2】:

这似乎是 .net 4.6.2 的一个错误。将框架更新到 .net 4.7 解决了这个问题。

我 80% 确定它与此错误有关:https://connect.microsoft.com/VisualStudio/Feedback/Details/3118586

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多