Monday, December 30, 2013

MICROSOFT SYNC FRAMEWORK WITH MSCRM 4.0 / MSCRM 2011


Sync Framework enables synchronization between databases. It provides an intuitive and flexible API that enables you to build applications that target offline and collaboration scenarios. The API enables you to use all or only some of the components that are provided, depending on the architecture and requirements of an application. Sync Framework supports client-server, client-to-client, and mixed topologies. In client-server topologies, all clients synchronize with a central server. In client-to-client topologies, each client can synchronize with another client without changes having to go through a central server. Mixed topologies consist of a combination of client-to-client and client-server topologies.

Sync Framework features technologies and tools that enable roaming, data sharing, and taking data offline. By using Sync Framework, developers can build synchronization ecosystems that integrate any application with data from any store, by using any protocol over any network.

Architecture:

Sync Framework uses a provider-based architecture. Providers shield other synchronization components from the complexities and specific implementation of each data store. This architecture, coupled with the use of specialized synchronization metadata, enables Sync Framework to synchronize any type of data store for which a provider is written. Sync Framework includes providers for common data stores, such as databases and the NTFS file system, and lets you write providers for other types of stores. The provider is the main integration point into Sync Framework.
The following illustration shows the high-level architecture of Sync Framework. Synchronization always occurs between two replicas (or nodes) as shown in the illustration, but synchronization communities (or topologies) can be of any shape, such as hub-and-spoke, peer-to-peer, and so on. With some exceptions, each pair of participants can synchronize over a 2-tier architecture or an n-tier architecture, as application requirements dictate. The documentation for each Sync Framework component provides more detailed information about appropriate architectures and security considerations.

The elements in the illustration are of three types:
  •      Elements that are written by the developer.
  •      Elements that are provided by Sync Framework.
  •      Elements that are either written by the developer or provided by Sync Framework, depending on the scenario.



Supported Operating Systems:

Operating system
Edition
Processor type
Windows XP Service Pack 3
Home and Professional
32-bit, 64-bit, WOW64
Windows Vista
Starter, Home Basic, Home Premium, Business, Enterprise, and Ultimate
32-bit, 64-bit, WOW64
Windows 7
Starter, Home Basic, Home Premium, Professional, Enterprise, and Ultimate
32-bit, 64-bit, WOW64
Windows Server 2003 and R2
Standard, Enterprise, and Datacenter
32-bit, 64-bit, WOW64
Windows Server 2008 and R2
Standard, Enterprise, and Datacenter
32-bit, 64-bit, WOW64


Configuring CRM and Custom Database:

Configuring Databases

1.     You can configure a CRM database from the CRM installed server that will be used by the Sync Service. In our case, we are syncing the data with “Account” entity
2.     You can configure Custom Database that will be used by the Sync service. In our case, we are syncing data for DEV_DATA(database) with “SyncAccount” table.  You have to create a table with specific set of columns that needs to be sync with CRM database.

Defining Scope and Provisioning a CRM database

To prepare the server database for synchronization, you will need to describe a sync scope and provision the server database with scope related artifacts.
By describing a sync scope, you define what you want to synchronize. A sync scope is a set of tables that must be synchronized as a single unit. The tables can already exist in the database or they can be described by using the Sync Framework object model and then be generated at runtime when the underlying store is provisioned. The provisioning of a database involves adding sync scope related artifacts such as tracking tables, triggers, and stored procedures to the database. These artifacts are used by the synchronization process at runtime.
1.     Launch Visual Studio 2012: Click Start, point to Programs, point to Microsoft Visual Studio 2012, and then click Microsoft Visual Studio 2012.
2.     Click File on menu bar, point to New, and click Project.
3.     Select Visual C# from Project Types, and select Console Application from Templates.
4.     Type ProvisionServer for the project name, C:\ for Location, and ProvisionServer for Solution Name.
5.     Click OK to close the New Project dialog box.
6.     In the Solution Explorer window, right-click ProvisionServer, and click Add Reference.
7.     Select Microsoft.Synchronization, Microsoft.Synchornization.Data, Microsoft.Synchronization.Data.SqlServer on the .NET tab. These are the assemblies shipped with Microsoft Sync Framework.
8.     Click OK to close the Add Reference dialog box.
9.     Add the following using statements to the beginning of the Program.cs file after the existing using statements. These namespaces contains the classes that you will be using in the code for this console application.
using System.Data.SqlClient;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
using Microsoft.Synchronization.Data.SqlServerCe;
10.   Add the following statement to the Main method to create a connection to the MSCRM server database.
SqlConnection serverConn = new SqlConnection(ConfigurationManager.AppSettings["serverCon"]);
11.  Add the following code to the Main method to define a sync scope. This code creates the AccountScope sync scope, gets the description of Products table in the MSCRM database, and adds the description to the AccountScope. The high level steps for defining a sync scope are:
1.     Create an instance of the DbSyncScopeDescription class. The DbSyncScopeDescription class is used to specify the name of the sync scope and the list of tables to be synchronized. The tables are specified using the DbSyncTableDescription class.
2.     Create an instance of the DbSyncTableDescription class based on the schema of Products table retrieved from the MSCRM server database. The DbSyncTableDescription class is used to specify the name of the table, columns of the table to be synchronized, data types of the table, and other information that is required for the sync. This information can be specified explicitly or it can be obtained by querying the database using the GetDescriptionForTable (String, SqlConnection) method.
3.     In this walkthrough, you will use the GetDescriptionForTable(String, SqlConnection) method of the SqlSyncDescriptionBuilder class to retrieve the description of the table.
4.     Add the DbSyncTableDescription object to Tables collection of the DbSyncScopeDescription object using the Add method.
              SqlConnection serverConn = new SqlConnection(serverCon);
               // define a new scope
               DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(ConfigurationManager.AppSettings["globalName"] + "Scope");
               // get the description of the Products table from SyncDB dtabase
DbSyncTableDescription tableDesc = SqlSyncDescriptionBuilder.GetDescriptionForTable(entityName[0], baseColumns, serverConn);

DbSyncTableDescription tableDesc1 = SqlSyncDescriptionBuilder.GetDescriptionForTable(entityName[1], exBaseColumns, serverConn);

              tableDesc.GlobalName = ConfigurationManager.AppSettings["globalName"];
              tableDesc1.GlobalName = ConfigurationManager.AppSettings["globalName"];

              // add the table description to the sync scope definition
              scopeDesc.Tables.Add(tableDesc);
              scopeDesc.Tables.Add(tableDesc1);
12.   Add the following code to the Main method to provision the MSCRM server database with sync related artifacts. This code creates a SqlSyncScopeProvisioning object, skips the creation of Products table on the server since the table already exists, and provisions the MSCRM database with scope related artifacts. The high level steps for provisioning the server database with sync scope related artifacts are:
1.       Create an instance of the SqlSyncScopeProvisioning class based on the DbSyncScopeDescription object and a connection to the server database. The SqlSyncScopeProvisioning class represents the provisioning of a SQL Server database for a particular scope that is represented by a DbSyncScopeDescription object.
2.       Invoke the SetCreateTableDefault(DbSyncCreationOption) method by specifying the DbSyncCreationOption value as Skip because the Products table already exists in the server database. The SetCreateTableDefault(DbSyncCreationOption) method is used to specify whether to create base tables when a scope is configured.
3.       Invoke the Apply() method on SqlSyncScopeProvisioning object to start the provisioning process, which creates the change-tracking infrastructure in the server database.
 // create a server scope provisioning object based on the scope
SqlSyncScopeProvisioning serverProvision = new SqlSyncScopeProvisioning(serverConn, scopeDesc);

               serverProvision.PopulateFromScopeDescription(scopeDesc);

               // skipping the creation of table since table already exists on server
               serverProvision.SetCreateTableDefault(DbSyncCreationOption.Skip);

               // start the provisioning process
               serverProvision.Apply();
13.  In Solution Explorer, right-click ProvisionServer, and click Build.
14.  Press Ctrl+F5 to execute the program.
15.  Press ENTER to close the command prompt window.
16.  In SQL Server Management Studio, expand MSCRM node, expand Tables, and you should see the following additional tables created by the provisioning process: AccountBase_Tracking,AccountExtensionBase_Tracking, schema_info, scope_config, and scope_info. There are also other database objects such as triggers and stored procedures created by the provisioning process.





Defining Scope and Provisioning a Custom database

You can continue with the same project “ProvisionServer” or create a new project if needed.  You can create a new function and call the same in the Main method of the Console Application. Repeat the same steps as mentioned in CRM database but need to replace the Connection string and table name. The following changes will get affected in the Custom DB after provisioning. There are also other database objects such as triggers and stored procedures created by the provisioning process.

Executing Synchronization

You can continue with the same project “ProvisionServer” or create a new project if needed. You can create a new function and call the same in the Main method of the Console Application. In this Function, copy the below code. Make sure that the scope name should be same as you mentioned in the Client and Server Provisioning(i.e ConfigurationManager.AppSettings["globalName"] + "Scope" in our case).
// create a connection to the custom database
               SqlConnection clientConn = new SqlConnection(clientCon);

               // create a connection to the CRM database
               SqlConnection serverConn = new SqlConnection(serverCon);

               // create the sync orhcestrator
               SyncOrchestrator syncOrchestrator = new SyncOrchestrator();

// set local provider of orchestrator to a sync provider associated with the AccountScope in the custom database
syncOrchestrator.LocalProvider = new SqlSyncProvider(ConfigurationManager.AppSettings["globalName"] + "Scope", clientConn);


// set the remote provider of orchestrator to a server sync provider //associated with the AccountScope in the Custom server database
syncOrchestrator.RemoteProvider = new SqlSyncProvider(ConfigurationManager.AppSettings["globalName"] + "Scope", serverConn);

               // set the direction of sync session to Upload and Download
               syncOrchestrator.Direction = SyncDirectionOrder.UploadAndDownload;

               // subscribe for errors that occur when applying changes to the client
               ((SqlSyncProvider)syncOrchestrator.LocalProvider).ApplyChangeFailed += new EventHandler<DbApplyChangeFailedEventArgs>(Program_ApplyChangeFailed);

              ((SqlSyncProvider)syncOrchestrator.LocalProvider).ChangesSelected += new EventHandler<DbChangesSelectedEventArgs>(Program_ChangesSelected1);

               ((SqlSyncProvider)syncOrchestrator.RemoteProvider).ChangesSelected += new EventHandler<DbChangesSelectedEventArgs>(Program_ChangesSelected);

               // execute the synchronization process
               SyncOperationStatistics syncStats = syncOrchestrator.Synchronize();

In the above code, the ChangesSelected event of LocalProvider will get the data from Custom Database table. The logic is written inside this event in such a way that the datatable (which we got it from the ChangesSelected event) has modified to get the specific set of data to create/update/delete the CRM records. The following sample piece of code is get the datatable of LocalProvider.
static void Program_ChangesSelected1(object sender, DbChangesSelectedEventArgs e)
 {
 
   if(e.Context.DataSet.Tables.Contains(ConfigurationManager.AppSettings["globalName"]))
    {
        var dataTable = e.Context.DataSet.Tables[ConfigurationManager.AppSettings["globalName"])];

       // Logic to push the data from Custom DB table to CRM DB table
     }
 }

Also, the ChangesSelected event of RemoteProvider will get the data from CRM database table. The logic is written in such a way that the datatable has modified to get a specific set of data to create/update/delete the Custom database records. The following sample piece of code is get the datatable of RemoteProvider.
static void Program_ChangesSelected(object sender, DbChangesSelectedEventArgs e)
 { 
   if(e.Context.DataSet.Tables.Contains(ConfigurationManager.AppSettings["globalName"]))
    {
        var dataTable = e.Context.DataSet.Tables[ConfigurationManager.AppSettings["globalName"])];

       // Logic to push the data from CRM DB table to Custom DB table
     }

 }

Configuration of Application Config:

Configuration of App.config:

You can specify the server names, table names, and column names in the App.config file of sample  format shown below. Update the specific values in the Config file and make sure that don’t modify/rename the key inside the App.config file.

<configuration>
  <appSettings>
    <!--Specify the table names for CRM and Custom database-->
    <add key="baseEntity" value="AccountBase"/>
    <add key="exBaseEntity" value="AccountExtensionBase"/>
    <add key="cEntity" value="SyncAccount"/>
    <add key="globalName" value="Account"/>
    <!--Specify the entityview for using CRM API in which pushing data from custom to CRM database -->
    <add key="crmEntityView" value="account"/>
    <!--Specify the database connections for the servers-->
    <add key="serverCon" value="Data Source=<<SQL server Name>>; Initial Catalog=<<database name>>; Integrated Security=True"/>
    <add key="clientCon" value="Data Source=<<SQL server Name>>; Initial Catalog=<<Custom database name>>; Integrated Security=True"/>
    <!--Specify the column(except currency and optionset columns) for the CRM DB (crm_1 - always be a mandatory field which should be from base table).Also we can have 'n' number of custom attributes-->
    <add key="crmkey" value="accountid"/>
    <add key="crm_1" value="name"/>
    <add key="crm_2" value="telephone1"/>
    <add key="crmex_1" value="new_noofbranches"/>
    <add key="crmex_2" value="new_test_bool"/>
    <add key="crmex_3" value="new_test_decimal"/>
    <add key="crmex_4" value="new_test_datetime"/>   
    <!--Specify the optionset colum for CRM DB -->
    <add key="crmOSet_1" value="industrycode"/>
    <add key="crmOSetex_1" value="new_test_optionset"/>   
     

<!--Define the column for the custom DB-->
    <add key="cuskey" value="accountid"/>
    <add key="cus_1" value="name"/>
    <add key="cus_2" value="telephone1"/>
    <add key="cusex_1" value="new_NoofBranches"/>
    <add key="cusex_2" value="new_Test_bool"/>
    <add key="cusex_3" value="new_Test_Decimal"/>
    <add key="cusex_4" value="new_Test_Datetime"/>
    <!--Specify the currency related colum for Custom DB -->
    <add key="cusMon_1" value="revenue"/>
    <add key="cusMonex_1" value="new_Test_Money"/>

    <!--Specify the optionset colum for Custom DB -->
    <add key="cusOSet_1" value="industrycode"/>
    <add key="cusOSetex_1" value="new_test_optionset"/>   
  </appSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

Happy Coding :) 

No comments:

Post a Comment