Dynamics 365 - 使用 IOrganizationService 创建 OrganizationServiceProxy
Dynamics 365 - Create OrganizationServiceProxy using IOrganizationService
我有一个自定义实体的处理程序 class(一些 sdk 请求在此处处理),并且在许多 plugins/classes 中引用了此处理程序。必须通过管理上下文而不是调用用户来访问该实体。我们没有将服务 "that is created over admin guid" 传递给处理程序 class,而是试图在处理程序 class 中模拟服务。例如;
----- 插件内部 -----
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
在我的实体处理程序中,首先将 IOrganizationService 实例的 CallerID 转换为 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: Object reference not set to an instance of an object.'。
有没有办法做这样的事情。我希望我自己解释得足够好,谢谢...
您可以传递 null
以便系统用户可以在 CreateOrganizationService
期间被工厂冒充。
// Use the factory to generate the Organization
Service.OrganizationServiceImpersonated = factory.CreateOrganizationService(null);
这并不能正常工作,因为传递给插件的对象不是 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...)
我有一个自定义实体的处理程序 class(一些 sdk 请求在此处处理),并且在许多 plugins/classes 中引用了此处理程序。必须通过管理上下文而不是调用用户来访问该实体。我们没有将服务 "that is created over admin guid" 传递给处理程序 class,而是试图在处理程序 class 中模拟服务。例如;
----- 插件内部 -----
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
在我的实体处理程序中,首先将 IOrganizationService 实例的 CallerID 转换为 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: Object reference not set to an instance of an object.'。 有没有办法做这样的事情。我希望我自己解释得足够好,谢谢...
您可以传递 null
以便系统用户可以在 CreateOrganizationService
期间被工厂冒充。
// Use the factory to generate the Organization
Service.OrganizationServiceImpersonated = factory.CreateOrganizationService(null);
这并不能正常工作,因为传递给插件的对象不是 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...)