Обновление до.net 4.6.2 из.net 4.5.2 вызывает исключение ссылки на объект для метода ExecuteCore в xrm sdk
У нас есть приложение магазина Win 8.1, которое разработано на основе платформы.net 4.5.2. Когда компьютер обновляется до.net 4.6.2, мы получаем, что для ссылки на объект не установлено значение исключения объекта.
Приложение состоит из двух частей: приложение-хранилище, в котором хранится вся логика пользовательского интерфейса, и агент, который содержит все взаимодействия уровня данных с соединителем Outlook Dynamics CRM.
Я определил строку, в которой происходит ошибка на base.ExecuteCore(запрос) при выполнении первого запроса, который является WhoAmI.
Интересно, что тот же код работает, если агент запущен в режиме отладки или используется в консольном приложении. Агент запускается нашим приложением с использованием URL-адреса приложения и подтверждается, что он запущен.
Я пробовал следующее:
- Обновление проекта до.net 4.6.2
- Обновление связанных пакетов nuget до их последних версий, в том числе xrm sdk dll.
- Декомпиляция dll Xrm.SDK и проверка каждого свойства, используемого в методе, для поиска места ошибки, и обнаружение всех соответствующих свойств, которые должны быть установлены.
- Обход коннектора 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(запрос OrganizationRequest) в CrmProxy.CrmOrganizationProxy.ExecuteWW.Mobility.CrmProxy\CrmContextProvider.cs: строка 127
Учебный класс:
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;
}
}
}
}
ОБНОВЛЕНИЕ 17/07/2017
У меня теперь есть более подробная ошибка после изменения кода ниже.
Ошибка:
LastCrmError = "Невозможно войти в Dynamics CRMOrganizationServiceProxy is null"
Код:
var crmProxy = new CrmServiceClient("Url=http://crm/AdventureWorks;");
crmProxy.GetMyCrmUserId();
После добавления регистрации на основе файлов, я думаю, что получаю полезную ошибку
Значение OperationContext.Current не является значением OperationContext, установленным этим OperationContextScope.
Трассировка стека: в System.ServiceModel.OperationContextScope.PopContext() в Microsoft.Xrm.Sdk.Client.ServiceContextInitializer1.Dispose(логическое удаление) в Microsoft.Xrm.Sdk.Client.ServiceContextInitializer1.Drpose (at).Client.DiscoveryServiceProxy.Execute(запрос DiscoveryRequest) в Microsoft.Xrm.Tooling.Connector.CrmWebSvc.DiscoverOrganizations(Uri discoveryServiceUri, Uri homeRealmUri, ClientCredentials clientCredentials, ClientCredentials deviceCredentials)
2 ответа
Это похоже на ошибку в.net 4.6.2. Обновление платформы до.net 4.7 решило эту проблему.
Я на 80% уверен, что это связано с этой ошибкой: https://connect.microsoft.com/VisualStudio/Feedback/Details/3118586
Возможно, попробуйте создать экземпляр 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;"/>
Локальная IFD до CRM 2016:
<add name="prod" connectionString="Url=https://contoso.litware.com; Username=someone@litware.com; Password=password; AuthType=IFD;"/>
Локальный IFD для CRM 2016 и более поздних версий (v8.0+)
<add name="prod" connectionString="ServiceUri=https://contoso.litware.com/contoso; Domain=contoso; Username=contoso\administrator; Password=password; AuthType=IFD; LoginPrompt=Never;" />