Sunday, May 20, 2012

MS CRM 2011: Data transferring between systems

I think a lot of developers faces with integration between systems. It could be connection between CRM and accounting systems. To track changes that appeared at CRM and should be transmitted to other system I use plugins but how to understand what was the source of this changes – user of CRM system or synchronization service – this is the question. I use following approach to solve this issue:
Of course it is possible to create some special integration account and not track all changes applied under this account. My idea was to reuse existing Integration account. Following code I use in synchronization service to create instance of IOrganizationService and impersonate as ‘Integration’ user:
private static IOrganizationService GetOrganizationService(Uri serviceUrl, 
    NetworkCredential credential)
{
    ClientCredentials credentials = new ClientCredentials();
    credentials.Windows.ClientCredential = credential;

    OrganizationServiceProxy proxy = new OrganizationServiceProxy(serviceUrl, 
        null, credentials, null);

    QueryByAttribute query = new QueryByAttribute("systemuser");
    query.AddAttributeValue("fullname", "integration");
    query.ColumnSet = new ColumnSet(false);

    DataCollection<Entity> users = proxy.RetrieveMultiple(query).Entities;
    if (users.Count == 0)
        throw new Exception("Integration user was not found!");

    proxy.CallerId = users[0].Id;
    return (IOrganizationService)proxy;
}

Following code I use inside ‘tracking’ plugins at the side of CRM:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Data.SqlClient;

namespace XRMSolutions.Plugins
{
    public class OperationHandler : IPlugin
    {

        #region Privates

        private Guid _integrationUserId = Guid.Empty;

        #endregion Privates

        #region IPlugin members

        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = 
            (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            #region Integration User Lookup

            if (_integrationUserId == Guid.Empty)
            {
                IOrganizationServiceFactory serviceFactory = 
                (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService crmservice = serviceFactory.CreateOrganizationService(null);

                QueryExpression query = new QueryExpression("systemuser");
                query.ColumnSet = new ColumnSet(false);
                query.Criteria.AddCondition("fullname", ConditionOperator.Equal, 
                    new object[] { "integration" });

                EntityCollection users = crmservice.RetrieveMultiple(query);
                if (users.Entities.Count == 0)
                    return;

                _integrationUserId = (Guid)users[0]["systemuserid"];
            }

            #endregion Integration User Lookup

            if (context.UserId == _integrationUserId)
                return;

            //Here you should put code which would be used for tracking of changed data
        }

        #endregion IPlugin members

    }
}

That’s it. I wish you good and interesting integration projects!

2 comments:

  1. It's better to use IntegrationUserId attribute of the Organization entity to determine id of a system account.

    p.s. You can get OrganizationId from plugin context.

    ReplyDelete
    Replies
    1. Thanks, your opinion is very important for me!

      Delete