This topic has not yet been rated - Rate this topic

How to: Deploy Sync Framework to Windows Azure

This topic shows you how to deploy Sync Framework components to a Windows Azure hosted service. It also includes suggestions for how to create an N-tier application that synchronizes data from a SQL Azure database to a SQL Server database on another computer.

Storing your data on SQL Azure Database allows you to take advantage of many benefits, such as secure access to your data from any computer that can connect to the Internet. However, there may be times when you are forced to use a network that is slow or unreliable. By using Sync Framework to synchronize data between a SQL Azure database and a SQL Server database on your local computer, you can work with data on your local computer instead of data on the Internet. This allows you to reduce network traffic, to increase the reliability of access to your data, even to work without a network connection, all while keeping your local database up-to-date with your SQL Azure database.

Two typical ways to structure an application that synchronizes a SQL Server database with a SQL Azure database are to use a 2-tier architecture or an N-tier architecture.

  • 2-tier architecture: Sync Framework runs on your local computer and uses a SqlSyncProvider object to connect to your SQL Azure database as with any other SQL Server database. For more information on how to accomplish this, see How to: Configure and Execute Synchronization with SQL Azure.

  • N-tier architecture: A Sync Framework database provider runs in a Windows Azure hosted service and communicates with a proxy provider that runs on your local computer. The synchronization application runs on your local computer and connects a database provider that represents your local database with a proxy provider that communicates with your Windows Azure service. Your Windows Azure service consists primarily of a SqlSyncProvider database provider that runs in a Windows Azure Web role or worker role and represents your SQL Azure database.

For more information about synchronization architecture, see Architecture and Classes for Database Synchronization.

For a complete working sample of a Windows Azure hosted service and a client application that communicate by using Windows Communication Foundation (WCF) to synchronize between SQL Azure and SQL Server Compact databases, see Windows Azure Sync Service Sample and Walkthrough of Windows Azure Sync Service Sample.

There are several steps to complete before you can synchronize with a SQL Azure database.

  1. Provision your SQL Azure database for synchronization. This creates tracking tables and stored procedures in your database that are needed for synchronization. Because this is an administrative task, it does not need to be included in the Windows Azure service. Instead, you can provision the database by connecting to the SQL Azure database from your computer by using the Sync Framework provisioning methods. For an example of how to provision a SQL Azure database, see How to: Configure and Execute Synchronization with SQL Azure.

  2. Define your Windows Azure service interface. Create a component that implements this interface, runs in a Windows Azure Web role, and calls a SqlSyncProvider object to perform synchronization tasks. Create a proxy provider that runs on your local computer and communicates with your Windows Azure service.

  3. Deploy your service application, including Sync Framework components, to a Windows Azure hosted service.

  4. Connect the local database provider with the proxy provider and synchronize.

Defining and Implementing the Service Interface and Proxy Provider

In an N-tier architecture, the Windows Azure hosted service is the middle tier that communicates between the proxy provider on the local machine and the SQL Azure database. The way the proxy provider communicates with the service application is defined by you, as is the implementation of the proxy provider and the implementation of the service application component that calls the SqlSyncProvider database provider in your Windows Azure hosted service. A typical design for these components is as follows:

  1. Define a Windows Communication Foundation (WCF) service contract interface that includes all the necessary methods for synchronization, such as GetChangeBatch and ProcessChangeBatch.

  2. Create a component that implements the methods of the service contract and calls a SqlSyncProvider object to operate on the SQL Azure database.

  3. Deploy this component and required Sync Framework components to a Web role in a hosted service on Windows Azure. You may also decide to create a worker role that performs some of the processing for your application and communicates directly with the components in your Web role. Deploy these components now as well.

  4. Create a proxy provider that implements KnowledgeSyncProvider, runs on your local computer, and makes calls to the service interface implemented by your Windows Azure hosted service.

Implementing the service interface and proxy provider can be quite complex. For an example of a synchronization application that uses WCF to communicate with a Windows Azure hosted service and synchronizes with a SQL Azure database, see Windows Azure Sync Service Sample.

Deploying Sync Framework Components to Windows Azure

A Windows Azure hosted service application uses Sync Framework components as private assemblies. This guarantees that your service application uses just the set of Sync Framework components you require, and that your service application is not affected by Sync Framework components used by any other application. After your service application is set up to use Sync Framework private assemblies, deploy your application the same way you deploy any hosted service to Windows Azure.

Security note Security Note

Private assemblies do not get automatic security updates so the service owner must install all necessary updates of Sync Framework components.

To set up your service application to use Sync Framework components as private assemblies, complete the following steps:

  1. Install the Sync Framework 2.1 SDK to your local computer. The SDK can be found here: MSDN Sync Framework Developer Center. Because Windows Azure is a 64-bit platform, you must copy the 64-bit assemblies. The 32-bit assemblies will not function properly on Windows Azure. By default, the Sync Framework 64-bit assemblies are installed to C:\Program Files (x86)\Microsoft SDKs\Microsoft Sync Framework\2.1\Runtime\ADO.NET\V3.1\x64 for the database provider assemblies, and C:\Program Files (x86)\Microsoft SDKs\Microsoft Sync Framework\2.1\Runtime\x64 for the core assemblies.

  2. Copy the managed Sync Framework assemblies used by your application to the folder that contains your service application assemblies. Because the Sync Framework assemblies are not in the global assembly cache on the Windows Azure server, the .NET Framework searches for them in the folder where your application assembly resides. The managed assemblies used for database synchronization are:

    • Microsoft.Synchronization.dll

    • Microsoft.Synchronization.Data.dll

    • Microsoft.Synchronization.Data.SqlServer.dll

  3. Create a folder named “synchronization.assemblies” in the application root folder of your service application. Copy the unmanaged assemblies that your application requires from the Sync Framework installation folder to the synchronization.assemblies folder. The unmanaged assembly used for database synchronization is:

    • Synchronization21.dll

  4. Sync Framework uses COM to load the unmanaged assemblies. COM typically relies on the registry to locate assemblies. Instead of using the registry on Windows Azure, include two manifest files to help COM locate the private unmanaged assemblies.

    Create the first manifest file by creating a text file named “synchronization.assemblies.manifest” in the synchronization.assemblies folder. Copy the following information into this file:

    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
    <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
    
    <assemblyIdentity
       type="x64"
       name="synchronization.assemblies"
       version="2.1.0.0"
    />
    
      <file name = "synchronization21.dll">
        <comClass clsid="{EC413D66-6221-4ebb-AC55-4900FB321011}" threadingModel="Both"/>    
      </file>
    
    </assembly>
    
    
    

    Create the other manifest file by creating a text file named “webapp.manifest” in the application root folder. Copy the following information into this file:

    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    
      <assemblyIdentity name="webapp" version="8.0.0.0" type="x64"/>
    
      <dependency>
        <dependentAssembly>
    
          <assemblyIdentity name="synchronization.assemblies" version="2.1.0.0" type="x64"/>
        </dependentAssembly>
      </dependency>
    
    
    </assembly>
    
    
    

    For more information about private COM assemblies, see Isolated Applications and Side-by-Side Assemblies.

  5. Create an activation context in your application that is used to load the COM assemblies at runtime. To do this, create a class like the following in your project and call the CreateActivationContext method when your application starts, such as by overriding the Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint.OnStart method:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Runtime.InteropServices;
    using System.IO;
    
    namespace Microsoft.Samples.Synchronization
    {
        public class ActivationContext
        {
            // Activation Context API Functions 
    
            [DllImport("Kernel32.dll", SetLastError = true)]
            private extern static IntPtr CreateActCtx(ref ACTCTX actctx);
    
            // Activation context structure 
            private struct ACTCTX
            {
                public int cbSize;
                public uint dwFlags;
                public string lpSource;
                public ushort wProcessorArchitecture;
                public ushort wLangId;
                public string lpAssemblyDirectory;
                public string lpResourceName;
                public string lpApplicationName;
            }
    
            private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
            private const int ACTCTX_FLAG_SET_PROCESS_DEFAULT = 0x00000010;
            private IntPtr m_hActCtx = (IntPtr)0;
            public const UInt32 ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET = 14011;
    
            /// <summary>
            /// Explicitly load a manifest and create the process-default activation 
            /// context. It takes effect immediately and stays there until the process exits. 
            /// </summary>
            static public void CreateActivationContext()
            {
                string rootFolder = AppDomain.CurrentDomain.BaseDirectory;
                string manifestPath = Path.Combine(rootFolder, "webapp.manifest");
                UInt32 dwError = 0;
    
                // Build the activation context information structure 
                ACTCTX info = new ACTCTX();
                info.cbSize = Marshal.SizeOf(typeof(ACTCTX));
                info.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
                info.lpSource = manifestPath;
                if (null != rootFolder && "" != rootFolder)
                {
                    info.lpAssemblyDirectory = rootFolder;
                    info.dwFlags |= ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
                }
    
                dwError = 0;
    
                // Create the activation context 
                IntPtr result = CreateActCtx(ref info);
                if (-1 == result.ToInt32())
                {
                    dwError = (UInt32)Marshal.GetLastWin32Error();
                }
    
                if (-1 == result.ToInt32() && ActivationContext.ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET != dwError)
                {
                    string err = string.Format("Cannot create process-default win32 sxs context, error={0} manifest={1}", dwError, manifestPath);
                    ApplicationException ex = new ApplicationException(err);
                    throw ex;
                }
            }
        }
    }
    
    
    
    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports System.Web
    Imports System.Runtime.InteropServices
    Imports System.IO
    
    Namespace Microsoft.Samples.Synchronization
        Public Class ActivationContext
            ' Activation Context API Functions 
    
            <DllImport("Kernel32.dll", SetLastError := True)> _ 
            Private Shared Function CreateActCtx(ByRef actctx As ACTCTX) As IntPtr
            End Function
    
            ' Activation context structure 
            Private Structure ACTCTX
                Public cbSize As Integer
                Public dwFlags As UInteger
                Public lpSource As String
                Public wProcessorArchitecture As UShort
                Public wLangId As UShort
                Public lpAssemblyDirectory As String
                Public lpResourceName As String
                Public lpApplicationName As String
            End Structure
    
            Private Const ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID As Integer = &H4
            Private Const ACTCTX_FLAG_SET_PROCESS_DEFAULT As Integer = &H10
            Private m_hActCtx As IntPtr = DirectCast(0, IntPtr)
            Public Const ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET As UInt32 = 14011
    
            ''' <summary>
            ''' Explicitly load a manifest and create the process-default activation 
            ''' context. It takes effect immediately and stays there until the process exits. 
            ''' </summary>
            Public Shared Sub CreateActivationContext()
                Dim rootFolder As String = AppDomain.CurrentDomain.BaseDirectory
                Dim manifestPath As String = Path.Combine(rootFolder, "webapp.manifest")
                Dim dwError As UInt32 = 0
    
                ' Build the activation context information structure 
                Dim info As New ACTCTX()
                info.cbSize = Marshal.SizeOf(GetType(ACTCTX))
                info.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT
                info.lpSource = manifestPath
                If rootFolder IsNot Nothing AndAlso "" <> rootFolder Then
                    info.lpAssemblyDirectory = rootFolder
                    info.dwFlags = info.dwFlags Or ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID
                End If
    
                dwError = 0
    
                ' Create the activation context 
                Dim result As IntPtr = CreateActCtx(info)
                If -1 = result.ToInt32() Then
                    dwError = DirectCast(Marshal.GetLastWin32Error(), UInt32)
                End If
    
                If -1 = result.ToInt32() AndAlso ActivationContext.ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET <> dwError Then
                    Dim err As String = String.Format("Cannot create process-default win32 sxs context, error={0} manifest={1}", dwError, manifestPath)
                    Dim ex As New ApplicationException(err)
                    Throw ex
                End If
            End Sub
        End Class
    End Namespace
    
    
    
  6. Your application is now ready to deploy to Windows Azure!

    For more information about how to deploy your application to Windows Azure, see Deploying a Service.

Using Visual Studio to Deploy Sync Framework Components to Windows Azure

This section contains step-by-step instructions to setup a Windows Azure Cloud Service project in Visual Studio such that the Sync Framework components are automatically deployed along with the service specific components.

  1. Open your Windows Azure Cloud Service project in Visual Studio if the project is not already open. In the Solution Explorer, right-click the Web Role project, point to Add, and then click Add Reference.

  2. Using the Add Reference dialog box, add references to Microsoft.Synchronization.dll, Microsoft.Synchronization.Data.dll, anddd Microsoft.Synchronization.Data.SqlServer.dll from Sync Framework 2.1 installation folder (ex: C:\Program Files (x86)\Microsoft Sync Framework\2.1)

  3. Multiple-select the four files you added to References, right-click, and then click Properties.

  4. In the Properties window, set the value of Aliases property to global and Copy Local property to True.

  5. Create a source file named activationcontext.cs file with the following content and add the file to Web Role project.

    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Runtime.InteropServices;
    using System.IO;
    
    namespace Microsoft.Samples.Synchronization
    {
        public class ActivationContext
        {
            // Activation Context API Functions 
    
            [DllImport("Kernel32.dll", SetLastError = true)]
            private extern static IntPtr CreateActCtx(ref ACTCTX actctx);
    
            // Activation context structure 
            private struct ACTCTX
            {
                public int cbSize;
                public uint dwFlags;
                public string lpSource;
                public ushort wProcessorArchitecture;
                public ushort wLangId;
                public string lpAssemblyDirectory;
                public string lpResourceName;
                public string lpApplicationName;
            }
    
            private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
            private const int ACTCTX_FLAG_SET_PROCESS_DEFAULT = 0x00000010;
            private IntPtr m_hActCtx = (IntPtr)0;
            public const UInt32 ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET = 14011;
    
            /// <summary>
            /// Explicitly load a manifest and create the process-default activation 
            /// context. It takes effect immediately and stays there until the process exits. 
            /// </summary>
            static public void CreateActivationContext()
            {
                string rootFolder = AppDomain.CurrentDomain.BaseDirectory;
                string manifestPath = Path.Combine(rootFolder, "webapp.manifest");
                UInt32 dwError = 0;
    
                // Build the activation context information structure 
                ACTCTX info = new ACTCTX();
                info.cbSize = Marshal.SizeOf(typeof(ACTCTX));
                info.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
                info.lpSource = manifestPath;
                if (null != rootFolder && "" != rootFolder)
                {
                    info.lpAssemblyDirectory = rootFolder;
                    info.dwFlags |= ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
                }
    
                dwError = 0;
    
                // Create the activation context 
                IntPtr result = CreateActCtx(ref info);
                if (-1 == result.ToInt32())
                {
                    dwError = (UInt32)Marshal.GetLastWin32Error();
                }
    
                if (-1 == result.ToInt32() && ActivationContext.ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET != dwError)
                {
                    string err = string.Format("Cannot create process-default win32 sxs context, error={0} manifest={1}", dwError, manifestPath);
                    ApplicationException ex = new ApplicationException(err);
                    throw ex;
                }
            }
        }
    }
    
  6. Add a folder named synchronization.assemblies to the Web Role project and add the following five files to the folder.  Right-click the Web Role project, point to Add, and click New Folder. Type synchronization.assemblies for name of the folder.

    • Microsoft.Synchronization.dll

    • Microsoft.Synchronization.Data.dll

    • Microsoft.Synchronization.Data.SqlServer.dll

    • Synchronization21.dll

    • Create a file named synchronization.assemblies.manifest, add the following content, and add the file to this folder.

      
      <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
      <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
      
      <assemblyIdentity
         type="x64"
         name="synchronization.assemblies"
         version="2.1.0.0"
      />
      
        <file name = "synchronization21.dll">
          <comClass clsid="{EC413D66-6221-4ebb-AC55-4900FB321011}" threadingModel="Both"/>    
        </file>
      
      </assembly>
      
      
  7. Multiple-select all files under synchronization.assemblies folder, right-click, and then click Properties. Set the value of Build Action property to Content and Copy To Output Directory to Copy Always.

  8. Create a file named webapp.manifest, add the following content, and add the file to the Web Role project.

    
    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    
      <assemblyIdentity name="webapp" version="8.0.0.0" type="x64"/>
    
      <dependency>
        <dependentAssembly>
          <assemblyIdentity name="synchronization.assemblies" version="2.1.0.0" type="x64"/>
        </dependentAssembly>
      </dependency>
    </assembly>
    
  9. Set the value of Build Action property to Content and Copy To Output Directory to Copy Always for the webapp.manifest file using Properties window.

  10. Add the following statement to the OnStart method before base.OnStart method call in the WebRole.cs file.

    
    Microsoft.Samples.Synchronization.ActivationContext.CreateActivationContext();
    
    
Tip Tip

You will need to add clientaccesspolicy.xml file to the Web Role project if you want the Web Role to host the Silverlight application and set the Build Action property to Content and Copy to Output Directory to Copy Always using Properties window. Here is the content of a sample clientaccesspolicy.xml file.


<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>   
        <policy >   
            <allow-from http-request-headers="*">   
                <domain uri="*"/>   
                <domain uri="http://*"/>   
                <domain uri="file://*"/>   
            </allow-from>   
            <grant-to>   
                <resource path="/" include-subpaths="true"/>  
            </grant-to>
        </policy>  
    </cross-domain-access>  
</access-policy>
Did you find this helpful?
(1500 characters remaining)