简体   繁体   中英

Dynamics 365 - Create OrganizationServiceProxy using IOrganizationService

I have a handler class (some sdk requests are handled here) for a custom entity and this handler is referenced in many plugins/classes. This entity must be reached over admin context instead of calling user. Instead of passing the service "that is created over admin guid" to the handler class, we are trying to impersonate the service inside the handler class. For example;

----- Inside the Plugin -----

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

and inside my entity handler, change the CallerID of the IOrganizationService instance by casting it to the OrganizationServiceProxy first.

----- Inside the Handler -----

private IOrganizationService service;

public MyEntityHandler(IOrganizationService organizationService)

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

I get 'Exception: System.NullReferenceException: Object reference not set to an instance of an object.' in the casting part. Is there any way to do something like this. I hope i explained myself well enough, thanks...

This is not working simply because the object that is passed to the plugin is not OrganizationServiceProxy which is used in some external apps but not in the plugins. The object in plugins is different based on the isolation mode, as far as I remember for not-isolated mode it is Microsoft.Xrm.Extensibility.InprocessProxyService and for Sandbox mode it is Microsoft.Crm.Sandbox.SandboxOrganizationServiceWrapper . Both of these types are not in SDK, so you can access their properties only with reflection. The first one has CallerId property, so you should be able to access it using reflection, but the second one does not, so I don't think it's possible to replace this caller id.

The only valid approach that you should take is to pass IOrganizationServiceFactory to your handlers instead of IOrganizationService and then create IOrganizationService based on your needs. If you don't want to change your whole project structure (which I believe would be the best approach, but I already know that people are afraid of refactoring, for no good reason, and we end up in clumsy projects that have to rewritten after few years of such maintenance) just create a second constructor for your handler which will take IOrganizationServiceFactory as a parameter - this would keep your existing code intact and in handlers for which you need to use both admin and not-admin services, you will simply use the second constructor.

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

Or simply that way:

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

This is simply the example, of course I do not know much about your architecture, but for sure such approach would be much better, cleaner and easier to maintain in the future then what you are trying to do right now (for no good reason, again - don't be afraid of refactoring the code, most of the work would do Visual Studio for you...)

You can pass null so that System User can be impersonated by factory during CreateOrganizationService .

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

Read more

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM