1

I need to connect and retrieve records in CRM Online through CRM 365 plugin. I have tried simplified connection using xrm.tooling.dll but unfortunately it says Could not load file or assembly 'microsoft.xrm.tooling.connectorand when i used ClientCredential the error says Metadata contain refereces that cannot be resolved.

Strangely, i tried both method with console applcation and it's work prefectly. Just wanna knows what i miss in this case ? Do i need special requirement when i want to connect to CRM through plugin ? Please anybody share your knowledge.

EDIT

This just a sample code to get account name from CRM Online and display it using InvalidPluginExecutionException:

IOrganizationService _service;

public void Execute(IServiceProvider serviceprovider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
           {

                Entity ent = (Entity)context.InputParameters["Target"];

                if (ent.LogicalName != "opportunity")
                    return;

                string connstring = @"Url=https://office.crm5.dynamics.com; Username=username@office.onmicrosoft.com; Password=crmoffice; authtype=Office365";
                CrmServiceClient conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connstring);
                service = (IOrganizationService)conn.OrganizationWebProxyClient != null ? (IOrganizationService)conn.OrganizationWebProxyClient : 

(IOrganizationService)conn.OrganizationServiceProxy;


                try
                {
                    Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
                    Entity _account = new Entity("account");
                    _account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));

                    string x = _account["name"].ToString();


                    throw new InvalidPluginExecutionException("Result of Query : " + x);
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException(ex.Message);
                }
Fikri Hailal
  • 123
  • 2
  • 4
  • 16
  • you should already have the context information required to connect to CRM within the Plugin Execution Context. Can you please show your code? – jasonscript Feb 20 '17 at 05:26
  • @jasonscript hii, what is the meaning 'you should already have the context information required to connect to CRM' ? I'm never done this before, usually i created console application to retrieve records from CRM. I m new to this, please bare with me – Fikri Hailal Feb 20 '17 at 09:23

4 Answers4

2

You already have your connection to CRM using the IOrganizationService that you've defined on the third line of your plugin. Unless you need to connect to another CRM instance in a different org, there is no login needed or required.

Basically just delete the 4 lines above your try, and you should be good.

Edit:

public void Execute(IServiceProvider serviceprovider)
{
    IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
    IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
    IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);

    if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
    {

         Entity ent = (Entity)context.InputParameters["Target"];

         if (ent.LogicalName != "opportunity")
             return;

         Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
         Entity _account = new Entity("account");
         _account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));

         string x = _account["name"].ToString();


         throw new InvalidPluginExecutionException("Result of Query : " + x);
    }
}
Daryl
  • 18,592
  • 9
  • 78
  • 145
  • hi daryl, which lines should i delete ? And yes. i need to connect to another CRM instance within this plugin. The scenario is i retrieved data from crm online. the data will be used by Crm on-premise to fill its fields – Fikri Hailal Feb 20 '17 at 14:42
  • @FikriHailal Give that a shot. PS. I'd edit out your User Id and Password if I were you. – Daryl Feb 20 '17 at 15:18
  • oh god, i forgot that one. Thanks for remind me. By deleting simplified connection just like your code above, how can i communicated with another CRM instance ? – Fikri Hailal Feb 20 '17 at 15:26
  • Ah, @FikriHailal, so you are " connecting to another CRM instance in a different org"? In that case keep your code, and use ILMerge to merge in your assemblies that are missing "microsoft.xrm.tooling.connector" – Daryl Feb 20 '17 at 15:36
  • @Daryl you don't need tooling to connect to CRM online. I've posted my answer below, it does not use any tooling and I successfully connected to CRM online. – Pawel Gradecki Mar 18 '17 at 11:21
2

You do not need any additional libraries like Microsoft.Xrm.Tooling.Connector or others from SDK to consume CRM web services. Standard .NET mechanism related to SOAP / REST protocols will be enough (but of course this method may be little more difficult).

EDIT: I've made some additional investigation and it occurs that configuring auto-generated OrganizationServiceClient for Office365 authentication without using SDK libraries may be real pain in the ass. I'm not telling it is not possible however it is not documented by Microsoft. To add more details OAuth authentication is not supported by Visual Studio generated proxy classes.

Because of that - my second recommendation is to use facade web service communicating with CRM OnLine. You may host this web service on Windows Azure or any other cloud/hosting place in the internet. From your CRM 365 Plugin you may consume your custom web service methods and communicate with your CRM Online instance using this service. I suppose it will be much better approach that trying to run undocumented methods of connecting to CRM Online.**

Piotr Gaszewski
  • 343
  • 3
  • 15
  • Hi @piotr, can you show me a little snippet code how to do that ? – Fikri Hailal Feb 21 '17 at 10:04
  • I will talk to my manager for that option. It's strange that the other person is able to connect to crm online through the plugin. But failed with mine. Anyways, thanks for answer my questin – Fikri Hailal Feb 23 '17 at 08:04
2

You should be able to connect to another CRM instance without using any assemblies that are outside Online Sandbox (so other than Microsoft.Xrm.Sdk and related). Simply use the sample from SDK from "SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs". Simplified version for connecting to Office365 looks like that:

class AuthenticateWithNoHelp
{
    private String _discoveryServiceAddress = "https://disco.crm.dynamics.com/XRMServices/2011/Discovery.svc";
    private String _organizationUniqueName = "orgname";
    private String _userName = "admin@orgname.onmicrosoft.com";
    private String _password = "password";
    private String _domain = "domain";

    public void Run()
    {
        IServiceManagement<IDiscoveryService> serviceManagement =
                    ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
                    new Uri(_discoveryServiceAddress));
        AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;

        AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);


        String organizationUri = String.Empty;
        using (DiscoveryServiceProxy discoveryProxy =
            GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
        {
            if (discoveryProxy != null)
            {
                OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
                organizationUri = FindOrganization(_organizationUniqueName,
                    orgs.ToArray()).Endpoints[EndpointType.OrganizationService];

            }
        }

        if (!String.IsNullOrWhiteSpace(organizationUri))
        {
            IServiceManagement<IOrganizationService> orgServiceManagement =
                ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
                new Uri(organizationUri));

            AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);

            using (OrganizationServiceProxy organizationProxy =
                GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
            {
                organizationProxy.EnableProxyTypes();
                Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
                    new WhoAmIRequest())).UserId;
            }
        }
    }

    private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
    {
        AuthenticationCredentials authCredentials = new AuthenticationCredentials();

        authCredentials.ClientCredentials.UserName.UserName = _userName;
        authCredentials.ClientCredentials.UserName.Password = _password;

        return authCredentials;
    }

    public OrganizationDetailCollection DiscoverOrganizations(
        IDiscoveryService service)
    {
        if (service == null) throw new ArgumentNullException("service");
        RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
        RetrieveOrganizationsResponse orgResponse =
            (RetrieveOrganizationsResponse)service.Execute(orgRequest);

        return orgResponse.Details;
    }

    public OrganizationDetail FindOrganization(string orgUniqueName,
        OrganizationDetail[] orgDetails)
    {
        if (String.IsNullOrWhiteSpace(orgUniqueName))
            throw new ArgumentNullException("orgUniqueName");
        if (orgDetails == null)
            throw new ArgumentNullException("orgDetails");
        OrganizationDetail orgDetail = null;

        foreach (OrganizationDetail detail in orgDetails)
        {
            if (String.Compare(detail.UrlName, orgUniqueName,
                StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                orgDetail = detail;
                break;
            }
        }
        return orgDetail;
    }

    private TProxy GetProxy<TService, TProxy>(
        IServiceManagement<TService> serviceManagement,
        AuthenticationCredentials authCredentials)
        where TService : class
        where TProxy : ServiceProxy<TService>
    {
        Type classType = typeof(TProxy);

        if (serviceManagement.AuthenticationType !=
            AuthenticationProviderType.ActiveDirectory)
        {
            AuthenticationCredentials tokenCredentials =
                serviceManagement.Authenticate(authCredentials);
            return (TProxy)classType
                .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
                .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
        }

        return (TProxy)classType
            .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
            .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
    }

    static public void Main(string[] args)
    {
        AuthenticateWithNoHelp app = new AuthenticateWithNoHelp();
        app.Run();
    }
}

You can simplify it further by removing part with DiscoveryService and directly calling:

https://orgname.api.crm.dynamics.com/XRMServices/2011/Organization.svc

This should work on Sandboxed plugins as it uses only Sdk assemblies.

Pawel Gradecki
  • 3,476
  • 6
  • 22
  • 37
0

You should be able to connect to another CRM instance without using any assemblies that are outside Online Sandbox (so other than Microsoft.Xrm.Sdk and related).

For example simply use the sample from SDK from SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs.

Valerio Bozz
  • 1,176
  • 16
  • 32
sreeman
  • 27
  • 4