Dynamics 365 - 使用IOrganizationService创建OrganizationServiceProxy

时间:2017-10-26 08:50:24

标签: c# dynamics-crm-online

我有一个自定义实体的处理程序类(这里处理了一些sdk请求),并且在许多插件/类中引用了这个处理程序。必须通过管理上下文访问此实体,而不是调用用户。我们试图模拟处理程序类中的服务,而不是将“通过管理guid创建的服务”传递给处理程序类。例如;

-----插件内部-----

IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Instead of doing something like this;
var adminOrganizationService = factory.CreateOrganizationService(Guid.Parse("~ADMINGUID~"));
MyEntityHandler myEntityHandler = new MyEntityHandler(adminOrganizationService);
// Use myEntityHandler

// What i want to do is, calling my entity handler with the service of calling user;

MyEntityHandler myEntityHandler = new MyEntityHandler(factory.CreateOrganizationService(context.UserId));
// Use myEntityHandler

在我的实体处理程序中,首先通过将其转换为OrganizationServiceProxy来更改IOrganizationService实例的CallerID。

-----处理程序内部-----

private IOrganizationService service;

public MyEntityHandler(IOrganizationService organizationService)

{  
            // This is what i have tried.
            service = organizationService;
            (service as OrganizationServiceProxy).CallerId = Guid.Parse("~ADMINGUID~");
}

我得到'异常:System.NullReferenceException:对象引用未设置为对象的实例。'在铸造部分。 有没有办法做这样的事情。我希望我能够很好地解释自己,谢谢...

2 个答案:

答案 0 :(得分:1)

这不起作用,因为传递给插件的对象不是OrganizationServiceProxy,而是在某些外部应用程序中使用但不在插件中。插件中的对象因隔离模式而异,据我记得非隔离模式为Microsoft.Xrm.Extensibility.InprocessProxyService,而沙箱模式为Microsoft.Crm.Sandbox.SandboxOrganizationServiceWrapper。这两种类型都不在SDK中,因此您只能使用反射访问其属性。第一个具有CallerId属性,因此您应该能够使用反射访问它,但第二个没有,所以我不认为可以替换此调用者ID。

您应采取的唯一有效方法是将IOrganizationServiceFactory传递给处理程序而不是IOrganizationService,然后根据您的需要创建IOrganizationService。如果你不想改变你的整个项目结构(我认为这是最好的方法,但我已经知道人们害怕重构,没有充分的理由,我们最终会陷入笨拙的项目,必须经过几年的维护后重写)只需为你的处理程序创建第二个构造函数,它将IOrganizationServiceFactory作为参数 - 这将保持现有代码的完整性和处理程序,你需要同时使用admin和not-admin服务,你只需使用第二个构造函数。

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

答案 1 :(得分:0)

您可以传递null,以便CreateOrganizationService期间工厂可以模拟系统用户。

// Use the factory to generate the Organization     
Service.OrganizationServiceImpersonated = factory.CreateOrganizationService(null);

Read more