Dynamics 365 - Создание OrganizationServiceProxy с использованием IOrganizationService
В моем проекте у меня есть обработчик для пользовательской сущности, который используется для некоторых запросов и т. Д. На этот обработчик / сущность ссылаются во многих плагинах /logger/tracer и т. Д., И эта сущность должна быть доступна через контекст администратора вместо вызова пользователя. И опять же, вместо передачи сервиса, который создается поверх guid администратора, который выглядит так;
----- Внутри плагина -----
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var adminOrganizationService = factory.CreateOrganizationService(Guid.Parse("~ADMINGUID~"));
MyEntityHandler myEntityHandler = new MyEntityHandler(adminOrganizationService);
// Use myEntityHandler
// What i do want to do is, calling my entity handler with the service of calling user , which looks like;
MyEntityHandler myEntityHandler = new MyEntityHandler(factory.CreateOrganizationService(context.UserId));
// Use myEntityHandler
и в моем обработчике сущности преобразуйте службу, переданную в качестве аргумента, в OrganizationServiceProxy и измените его callerID на adminid или просто измените CallerID "службы" IOrganizationService, приведя сначала к OrganizationServiceProxy.
----- Внутри обработчика -----
private IOrganizationService service;
public MyEntityHandler(IOrganizationService organizationService)
{
// This is what i have tried.
service = organizationService;
(service as OrganizationServiceProxy).CallerId = Guid.Parse("~ADMINGUID~");
}
Я получаю 'Exception: System.NullReferenceException: ссылка на объект не установлена на экземпляр объекта.' в литой части. Это в принципе так, есть ли способ сделать что-то подобное. Я надеюсь, что объяснил себя достаточно хорошо, спасибо...
2 ответа
Это не работает просто потому, что объект, который передается плагину, не OrganizationServiceProxy
который используется в некоторых внешних приложениях, но не в плагинах. Объект в плагинах отличается в зависимости от режима изоляции, насколько я помню, для неизолированного режима это Microsoft.Xrm.Extensibility.InprocessProxyService
и для режима песочницы это Microsoft.Crm.Sandbox.SandboxOrganizationServiceWrapper
, Оба этих типа отсутствуют в SDK, поэтому вы можете получить доступ к их свойствам только с помощью отражения. Первый из них имеет свойство CallerId, поэтому вы должны иметь к нему доступ, используя отражение, а второй - нет, поэтому я не думаю, что можно заменить этот идентификатор вызывающего абонента.
Единственный верный подход, который вы должны предпринять, это пройти IOrganizationServiceFactory
вашим обработчикам вместо IOrganizationService
а затем создать IOrganizationService
основываясь на ваших потребностях. Если вы не хотите менять всю структуру вашего проекта (что, я считаю, было бы лучшим подходом, но я уже знаю, что люди боятся рефакторинга без какой-либо веской причины, и мы заканчиваем неуклюжими проектами, которые необходимо переписать после несколько лет такого обслуживания) просто создайте второй конструктор для вашего обработчика, который займет IOrganizationServiceFactory
в качестве параметра - это сохранит ваш существующий код нетронутым, и в обработчиках, для которых вам нужно использовать службы как администратора, так и не администратора, вы просто будете использовать второй конструктор.
public class MyHandler
{
private IOrganizationService service;
private IOrganizationService adminService;
public MyHandler(IOrganizationService service)
{
this.service = service;
}
public MyHandler(IOrganizationServiceFactory factory, Guid userId) //instead of passing userId here, it would be better to pass it to the method that you want to perform
{
this.service = factory.CreateOrganizationService(userId);
this.adminService = factory.CreateOrganizationService(null);
}
}
Или просто так:
public class MyHandler
{
private IOrganizationService service;
private IOrganizationService adminService;
public MyHandler(IOrganizationService service)
{
this.service = service;
}
public MyHandler(IOrganizationService service, IOrganizationService adminService) : this(service)
{
this.adminService = adminService;
}
}
Это просто пример, конечно, я не очень разбираюсь в вашей архитектуре, но наверняка такой подход будет намного лучше, чище и легче поддерживать в будущем, чем то, что вы пытаетесь сделать прямо сейчас (без веской причины, опять же - не бойтесь рефакторинга кода, большая часть работы сделает Visual Studio для вас...)
Вы можете пройти null
так что пользователь системы может выдавать себя за фабрику CreateOrganizationService
,
// Use the factory to generate the Organization
Service.OrganizationServiceImpersonated = factory.CreateOrganizationService(null);