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);

Прочитайте больше

Другие вопросы по тегам