Skip to content

02 Generate Server and Client code

Sébastien Pertus edited this page May 28, 2014 · 1 revision

Create a synchronization application for Windows Store application

Here is a first sample where we will learn how to create a simple sync app for Windows 8.

We will focus on Windows 8 and we will focus on Windows Phone 8 in an other sample.

Installation

Once you have installed the nuget package, you will find the SyncSvcUtilUI.exe in the packages directory :

The Configuration file

All the sync generation process is based on a XML file which describe the tables, the columns, the scope etc …

To be able to create the file, we will use the SyncSvcUtilUI.exe. By the way, you can create this file without this tools, but at least, I advise you to use an existing file

  • Generate the Sync Configuration
  • Create a config file (name FabrikamConfig.config in this sample)
  • Make a connection with the database server (dont forget to test to be sure you can reach your database server)

|| |

Adding a scope : In this part, we will create a Scope : this scope will provide all the “stuff” mandatory to sync all the tables, with no filter.

  • The Config Name : Usually, the name, when you make a simple sync process with no filter is DefaultScope
  • The Schema Name is blank because our database use the default schema dbo (If you have an other schema, you need to provide the correct schema name here)
  • The Is Template Scope won’t be checked because we don’t make a synchronization with filters
  • The Enable Bulk Apply Procedures will be checked because SQL Server can use bulk methods (with TVP)

Don’t forget to Save, then select it in the listbox, then press Next.

Select Sync Tables : In this part we will add the required tables :

For this sample, we won’t use Filter clause, and we will select all the columns.

The important part here is to be sure that the order is correct. Don’t forget : The first table is mandatory to use the second table : When you create a Service Ticket, you need to know the Customer associated :)

| | | | | |

You have create the xml configuration file. Just be sure to save it :) Here is a part of my xml file (just removed some columns to be clear) :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="SyncConfiguration" type="Microsoft.Synchronization.ClientServices.Configuration.SyncConfigurationSection, SyncSvcUtil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowLocation="true" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" overrideModeDefault="Allow" restartOnExternalChanges="true" requirePermission="true" />
    </configSections>
    <SyncConfiguration>
        <SyncScopes>
            <SyncScope Name="DefaultScope" SchemaName="" IsTemplateScope="false"
                EnableBulkApplyProcedures="true">
                <SyncTables>
                    <SyncTable Name="[Customers]" GlobalName="" SchemaName="" IncludeAllColumns="true"
                        FilterClause="">
                        <SyncColumns>
                            <SyncColumn Name="ID" GlobalName="" SqlType="int" IsPrimaryKey="true"
                                IsNullable="false" />
                            <SyncColumn Name="FirstName" GlobalName="" SqlType="nvarchar"
                                IsPrimaryKey="false" IsNullable="true" />
                        </SyncColumns>
                    </SyncTable>
                    <SyncTable Name="[ServiceTickets]" GlobalName="" SchemaName=""
                        IncludeAllColumns="true" FilterClause="">
                        <SyncColumns>
                            <SyncColumn Name="ServiceTicketID" GlobalName="" SqlType="uniqueidentifier"
                                IsPrimaryKey="true" IsNullable="false" />
                            <SyncColumn Name="Title" GlobalName="" SqlType="nvarchar" IsPrimaryKey="false"
                                IsNullable="false" />
                        </SyncColumns>
                    </SyncTable>
                </SyncTables>
            </SyncScope>
        </SyncScopes>
        <Databases>
            <TargetDatabase Name="Fabrikam" DbServer=".\SQL2012" DbName="FabrikamFiber"
                UserName="" Password="" UseIntegratedAuth="true" />
        </Databases>
    </SyncConfiguration>
</configuration>

This file is the key of all the next parts : Database provision (or deprovision), web server generation code, window store application generation code (btw WP8 too)

The Database part

No that we have create the configuration file, we need to provision this database with all the metadatas, additional tables, triggers and stored procedures.

First of all, you will find the script of the database here (before provisioning) : [link database script]

Again, we will use the SyncSvcUtilUI.exe to make the provision. Be sure to specify the good configuration file, and select the Provision mode:

  • Provision : Will create all the mandatories tables, trigger, and stored procedure
  • Deprovision : Will drop the Sync Scope from the database : Be careful, deprovision wont delete the sync tables (If you have multipe scopes) this option
  • Deprovision complete store : Will drop ALL the sync mechanism from the database (for all metadatas and all scope already created)

| |

Here is the command line used to provision the database using the comand line tool :

syncsvcutil.exe 
/scopeconfig:"C:\Users\spertus\Documents\Visual Studio 2012\Projects\CODEPLEX\syncwinrt\Samples\Sample01\FabrikamConfig.config" 
/mode:provision 
/scopename:DefaultScope 

Web Server Part

This part is your server website. this Website is your proxy to the database, exposing your data for synchronization.

We need to :

  • Create an empty ASP.NET web application
  • Add the required assemblies for Sync Framework 2.1
  • Add the required Nuget package for Sync Toolkit for WinRT
  • Generate the code with SyncSvcUtilUi.exe (or command line SyncSvcUtil.exe) and add it to the website
  • Configure the generated code (indeed, you need to specify at least the connection string)

For the first three points, you can check the Installation Tutorial : [Tutorial Install]

We will use the SyncSvcUtilUI.exe to generate the code.

Step 1. Select code generation source:

  • Sepcify the path to your Config file.
  • Specify your scope (you may have 1 scope)
  • Sepcify the target database (again you may have only 1 database target)

Step 2. Select code generation Parameters:

  • Specify the target : must be Server
  • The output directory : Specify the root of your website project
  • Language : specify CS or VB
  • Namespace : You can specify your namespace. By default, it’s the scope name
  • Output file prefix : You can change the file prefix

| | | | | |

Here is the same steps with the command line tool :

syncsvcutil.exe 
/scopeconfig:"C:\Users\spertus\Documents\Visual Studio 2012\Projects\CODEPLEX\syncwinrt\Samples\Sample01\FabrikamConfig.config"
/scopename:DefaultScope 
/language:CS 
/namespace:DefaultScope 
/mode:codegen 
/target:server 
/directory:"C:\Users\spertus\Documents\Visual Studio 2012\Projects\CODEPLEX\syncwinrt\Samples\Sample01\Fabrikam.WebServer"

You will find the generated files in your Web Server directory.

Just include them in your project :

Here is the description of the files:

  • DefaultScopeEntities : Describe your entities
  • DefaultScopeSyncService : Service .svc which will handle all request from your client

Open the DefaultScopeSyncService.svc.cs file and configure your endpoint :

Here is the code of my file, where I have configured several properties :

  • ServerConnectionString : The connection to your SQL Server. My connection string is placed in the web.config file
  • SetEnableScope() : Because Sync can handle multiple scope, you need to specify the right scope for each .svc
  • SetDefaultSyncSerializationFormat() : You can choose between XML Atom and JSON format
  • SetConflictResolutionPolicy() : You can choose if Server or Client wins when a conflict occurred (we will go deeper for this part in a next chapter)
  • UseVerboseErrors : For debug, it’s more confortable to get the full description of the error. Dont forget to pass this value to false when you go in production
  • SetDownloadBatchSize() : If your data ar big, donwloading a simple file with Http could be a problem. if you have a HUGE amount of data, your server would probably miss memory. Enabling batch mode will ensure that your server wont make an OutOfMemoryException and your client will download multiple files instead of one big file.
    public class DefaultScopeSyncService : SyncService<DefaultScopeOfflineEntities>
    {

        public static void InitializeService(ISyncServiceConfiguration config)
        {
            // Connection string from web.config
            config.ServerConnectionString = ConfigurationManager.ConnectionStrings["FabrikamConnection"].ConnectionString;

            // The scope to use
            config.SetEnableScope("DefaultScope");

            // I want to discuss with the JSON format
            config.SetDefaultSyncSerializationFormat(SyncSerializationFormat.ODataJson);
            
            // The server is always true
            config.SetConflictResolutionPolicy(ConflictResolutionPolicy.ServerWins);

            // for debug purpose, I need the whole error details
            config.UseVerboseErrors = true;

            // Because my json may be huge, i enable the batch mode
            config.SetDownloadBatchSize(2 * 1024);
            
        }

Your server is ready. You can check if it works easily with your browser by going to the .svc url, like this :

The Client Part

The client part is very similar to the Server part. Again we need to generate the code for the client application.

We need to :

  • Create a Windows Store application. Be careful only Xaml application is currently supported by this toolkit
  • Add the required Nuget package for Sync Toolkit for WinRT
  • Generate the client code with SyncSvcUtilUi.exe (or the command line SyncSvcUtil.exe) and add it to the client project.

Like the Server side, here is the screenshot of the required step to generate the code. Don’t forget to :

  • Specify SQLite Client for the target
  • Specify the correct output directory to your windows store application project directory

| | | | | |

Again here is the command line :

syncsvcutil.exe 
/scopeconfig:"C:\Users\spertus\Documents\Visual Studio 2012\Projects\CODEPLEX\syncwinrt\Samples\Sample01\FabrikamConfig.config"
/language:CS 
/mode:codegen 
/target:SQLiteClient 
/directory:"C:\Users\spertus\Documents\Visual Studio 2012\Projects\CODEPLEX\syncwinrt\Samples\Sample01\Fabrikam.Client"

You will find the generated files in your project directory :

Here is the description of the generated code :

  • DefaultScopeEntities : Describe all your entities required by the synchronization process
  • DefaultScopeOfflineContext : this class is your client service object. It will support all the methods (like Sync()) and all the configuration needed to synchronize your application

Now, you are able to synchronize your application between your server and your client !

To be consistent, I have create a class ContextModel in the DataModel directory. Actually, this class will contain an instance of DefaultScopeOfflineContext, configured to be able to launch a synchronization.

You will see in the next code screenshot, that we just provides the mandatory's properties :

  • The SQLite database local path
  • The Format used to communicate with the server (JSON)
  • The .svc URI
  • The encapsulation of the SynchronizeAsync() method
   public class ContextModel
    {
        public static string SyncUri = "http://localhost:3764/DefaultScopeSyncService.svc";
        private DefaultScopeOfflineContext SyncContext { get; set; }

        public String DatabasePath { get; set; }
        public string DatabaseName { get; set; }

        public ContextModel()
        {
            // SQLite Path
            this.DatabaseName = "fabrikamfiber_sqlite.db";
            this.DatabasePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, this.DatabaseName);
            // Context
            this.SyncContext = new DefaultScopeOfflineContext(this.DatabaseName, new Uri(SyncUri, UriKind.Absolute));
            // Definition of the cache controller serialization format:
            this.SyncContext.CacheController.ControllerBehavior.SerializationFormat = SerializationFormat.ODataJSON;

        }

        public async Task<CacheRefreshStatistics> Sync()
        {
            try
            {
                var result = await this.SyncContext.SynchronizeAsync();

                // For debug time
                if (result.Error != null)
                    Debug.WriteLine(result.Error.Message);

                return result;

            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
                throw;
            }
        }
    }

We will see in an other chapter that this class will contains all the methods we need to check if the database exist, create the queries we need to select, update or delete our local database etc…