Tutorial: Creating and Consuming a WCF Sync Service
This tutorial contains three mandatory walkthroughs followed by an optional walkthrough. It also contains a topic that includes steps to troubleshoot service or client related issues.
Section | Description |
---|---|
Walkthrough: Creating a Sample Database | This walkthrough provides steps to create a sample database and to use the SyncSvcUtil utility to create sync related artifacts in the database. |
Walkthrough: Creating a Sync Service | This walkthrough provides steps to create a simple sync service. |
Walkthrough: Creating a Silverlight Offline Client Application | This walkthrough provides steps to develop an offline-capable Silverlight application that consumes a sync service. |
Optional: Deploying Service to IIS | This optional walkthrough provides steps to host the sync service in IIS instead of hosting it in an ASP .NET Development Server, and use the service from a Silverlight client application. |
Troubleshooting the Tutorial | This topic contains troubleshooting information for the tutorial. |
Walkthrough: Creating a Sample Database
In this walkthrough you will create a database that is used by the sample sync service and use the SyncSvcUtil utility to create sync related artifacts in the database.
Task 1: Creating a sample database
Open a command prompt with administrative rights and switch to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\Samples\Config folder.
Tip
If you install the Sync Framework 4.0 October 2010 CTP on a x64 computer, it will be installed in %ProgramFiles(x86)% or %SystemDrive%\Program Files (x86). Usually it is C:\Program Files (x86).
At the command prompt, type the following command and then press ENTER.
sqlcmd -S (local) -i instlistdb.sql
Important
In the previous command, replace the server name with your server’s instance name, if you are not using the default instance. For example: if your SQL Server instance is called MYSQLINSTANCE, replace (local) with .\MYSQLINSTANCE
The sqlcmd tool will report its progress (as shown below) as the ListDb database is installed and will then return control to the command prompt.
Output of sqlcmd command: Changed database context to 'master'. Changed database context to 'listdb'
Important
Make sure the SqlCmd.exe corresponds to the one in location C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE.
Here is the database diagram for the listdb database:
Leave this Command Prompt window open so that you can use it later in this walkthrough.
Task 2: Provisioning the database
In this task you will provision the database using the SyncSvcUtil.exe tool. To provision the database using SyncSvcUtilHelper.exe, a UI tool built on top of SyncSvcUtil.exe, see Server Scope Provisioning or Deprovisioning. Using this UI tool, you can also generate a new or edit an existing sync configuration XML file. See Creating or Editing a Sync Configuration File for more details.
In the Command Prompt window from Task 1, type the following command and then press ENTER.
..\..\bin\SyncSvcUtil /mode:provision /scopeconfig:listdbconfig.xml
Important
If you are using SQL Server 2005, turn off Bulk Provisioning by adding the attribute EnableBulkApplyProcedures to the SyncScope tag and setting the value of attribute to false in the configuration file. See the syntax for this attribute in Configuration File Description.
The SyncSvcUtil tool will provision the database with all sync related artifacts (tracking tables, etc…). You will see the output similar to the following:
Reading specified config file... Generating DbSyncScopeDescription for scope DefaultScope... Provisioning Database ListSample for template scope DefaultScope... SyncSvcUtil completed with no errors.
Important
The listdbconfig.xml file is configured to use with the default instance of SQL Server. If you have a named instance, open the listdbconfig.xml and modify the value of DBServer attribute of the TargetDatabase element. For example, if your SQL Server instance is named MYSQLINSTANCE, then replace DbServer=”.” with DbServer=”.\MYSQLINSTANCE”, the TargetDatabase element would look like: .
Walkthrough: Creating a Sync service
In this walkthrough you will create a simple sync service.
Pre-requisites
You must have the following products installed on your computer to practice this walkthrough.
Visual Studio 2008 SP1 or Visual Studio 2010 with C# language components.
If you are using x86 Windows computer, install only x86 version (SyncSDK-v2.1-x86-ENU.msi) of Sync Framework 2.1 SDK.
If you are using x64 Windows computer, install the following:
- x64 version (SyncSDK-v2.1-x64-ENU.msi) of Sync Framework 2.1 SDK
- The following two x86 redistribution packages of Sync Framework 2.1 from Sync Framework 2.1 Redistributable Packages.
- Synchronization-v2.1-x86-ENU.msi
- DatabaseProviders-v3.1-x86-ENU.msi
Note
In this walkthrough, you will be hosting a sync service in the Visual Studio Developer Server, which requires 32-bit components of Sync Framework 2.1 to run the service successfully. If you are actually deploying and hosting the service to IIS or Windows Azure, you just need 64-bit components. It is not possible have full 32-bit Sync Framework 2.1 SDK installed side-by-side with the 64-bit SDK; therefore you will have to install one version of SDK (64-bit) completely and only selected components of other version (32-bit) of SDK
Task 1: Generating code for sync service
In this task you will create code files for the service by using the SyncSvcUtil.exe tool.
Open a Command Prompt window with administrative rights, and switch to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\Samples\Config folder.
Note
If your computer has the x64 version of Windows, use c:\Program Files(x86) folder wherever c:\Program Files is mentioned in this tutorial to access Sync Framework 4.0 October 2010 CTP components.
To create code files for the service by using the SyncSvcUtil.exe tool, type the following command at the command prompt and then press ENTER.
..\..\bin\SyncSvcUtil /mode:codegen /target:server /scopeconfig:listdbconfig.xml
The tool creates three files: DefaultScopeEntities.cs, DefaultScopeSyncService.svc, DefaultScopeSyncService.svc.cs in the current folder (C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\samples\Config). You will use these files later in Task 2 when you create a Visual Studio project. Here is the sample output from the previous command:
Reading specified config file... Generating DbSyncScopeDescription for scope DefaultScope... Generating files... SyncSvcUtil completed with no errors.
Note
You can also use the SyncSvcUtilHelper, a UI tool built on top of SyncSvcUtil command-line tool, to generate server side code. See Generating Code for a Server, Generic Client, or Isolated Store Client for more details.
Task 2: Creating a Visual Studio project
In this task, you will create a Visual Studio project for the sync service.
Open Microsoft Visual Studio 2008 with Administrator permissions: Click Start, point to All Programs, point to Microsoft Visual Studio 2008, right-click Microsoft Visual Studio 2008, and then click Run as Administrator.
Caution
If you are using Microsoft Visual Studio 2010, use steps similar to preceding steps to launch Visual Studio 2010.
If the User Account Control dialog appears, click Continue.
From the File menu, click New and then click Project
In the New Project dialog, expand Visual C# in the project types list and select ASP.NET Web Application.
Enter the Name “ListService”. Click OK to create the project.
In the Solution Explorer, right-click the ListService project, point to Add, and then click Add Existing Item.
Navigate to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\samples\Config and select the 3 files (DefaultScopeEntities.cs, DefaultScopeSyncService.svc, DefaultScopeSyncService.svc.cs), and then click Add to add these files to the project.
Examine the Solution Explorer and make sure that the files appear in the project tree.
In the Solution Explorer, right-click the ListService project and point to Add, and then click Add Reference.
In the Add Reference dialog box, click Browse tab, navigate to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\server\Microsoft.Synchronization.Services.dll, and then click OK.
Keep the Visual Studio window open. You will use this in the next task to configure the service.
Task 3: Configuring the sync service
In this task, you will configure the service and build it.
In the Solution Explorer, expand the files under DefaultScopeSyncService.svc and then double-click DefaultScopeSyncService.svc.cs to open the file.
Uncomment the following lines in the InitializeService method.
config.ServerConnectionString = "connection string here"; config.SetEnableScope("scope name goes here");
Replace connection string here with the following:
Data Source=(local);Initial Catalog=listDb;Integrated Security=true
Tip
In the previous statement, replace the server name with your server’s instance name, if you are not using the default instance. For example: if your SQL Server instance is called MYSQLINSTANCE, then replace (local) with .\MYSQLINSTANCE.
Replace “scope name goes here” with DefaultScope.
Add the following lines of code to the InitializeService method.
// configure filter parameters used by the service config.AddFilterParameterConfiguration( "userid", "User", "@ID", typeof(System.Guid)); config.AddFilterParameterConfiguration( "userid", "Item", "@UserID", typeof(System.Guid)); config.AddFilterParameterConfiguration( "userid", "List", "@UserID", typeof(System.Guid)); config.AddFilterParameterConfiguration( "userid", "TagItemMapping", "@UserID", typeof(System.Guid)); // enable Diagnostic Dashboard feature for the service config.EnableDiagnosticPage = true; // enable verbose errors config.UseVerboseErrors = true;
Important
The table name (ex: User) and the parameter name (ex. @ID) correspond to the definitions in the listdbconfig.xml file that was used for provisioning the database.
From the Build menu, click Build Solution. This will build the solution.
In the Solution Explorer, right-click DefaultScopeSyncService.svc and then click Set As Start Page.
Press F5 to execute the project, it will open a Web browser and navigate to DefaultSyncScopeService.svc. Perform the following operations.
In the address bar of Web browser, add $syncScopes to the end of .svc address, and press ENTER to see all the scopes available from the sync service. For example: http://localhost:port/DefaultScopeSyncService.svc/$syncscopes.
Use the following syntax to see the metadata for defaultscope, which is the name of scope supported by the service: http://localhost: /DefaultScopeSyncService.svc/defaultscope/$metadata. Refresh (press F5) the Web page if you see a blank page.
Use the following syntax to see diagnostics information for the service: http::/localhost:port/DefaultScopeSyncService.svc/$diag.
Tip
If Visual Studio shows a Debugging Not Enabled prompt, click OK in the dialog box. This will modify the Web.config to enable debugging.
Walkthrough: Creating a Silverlight Offline Client Application
Pre-Requisites
You must have the following products/components installed on your computer.
- Visual Studio 2008 SP1 or Visual Studio 2010 with C# language components
- Silverlight 3 Tools for Visual Studio 2008 or Silverlight 4 Tools for Visual Studio 2010
Task 1: Generating Client Code
In this task, you will generate code files for a Silverlight client using the SyncSvcUtil.exe tool.
Open a Command Prompt window with administrative rights, and switch to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\Samples\Config folder.
Note
If your computer has the x64 version of Windows, use c:\Program Files(x86) folder wherever c:\Program Files is mentioned in this tutorial to access Sync Framework 4.0 October 2010 CTP components.
At the command prompt, type the following command and then press ENTER.
..\..\bin\SyncSvcUtil /mode:codegen /target:isclient /scopeconfig:listdbconfig.xml
The tool will create two files: DefaultScopeEntities.cs and DefaultScopeOfflineContext.cs in C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\Samples\Config folder.
Note
You can also use the SyncSvcUtilHelper, a UI tool built on top of SyncSvcUtil command-line tool, to generate the code that can be used to build an isolated store client. See Generating Code for a Server, Generic Client, or Isolated Store Client for more details.
These files will be used in the next task to create the Silverlight project.
Task 2: Creating a Visual Studio Silverlight Application
In this task, you will create a Visual Studio Silverlight project which will consume the sync service.
In the Solution Explorer window, right-click Solution ‘ListService’, point to Add, and then click New Project.
In the New Project dialog, expand Visual C# in the Project types: list and select the Silverlight project type.
Select Silverlight Application from the templates menu.
Type the name ListClient and then click OK to create the project.
Click OK on the New Silverlight Application dialog box.
In the Solution Explorer, right-click ListClient, point to Add, and then click Add Existing Item.
Navigate to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\samples\Config and select the 2 files (DefaultScopeEntities.cs, DefaultScopeOfflineContext.cs) and then click Add.
Examine the Solution Explorer and make sure that that the files appear in the project tree.
In the Solution Explorer, right-click ListClient project, point to Add, and then click Add Reference.
In the Add Reference dialog box, go to the Browse tab and navigate to C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\client\Silverlight.
Note
To develop Silverlight client application for Windows Phone 7, use the WP7 subfolder of C:\Program Files\Microsoft SDKs\Microsoft Sync Framework\4.0\client\WP7 folder.
Select Microsoft.Synchronization.ClientServices.dll and then click OK.
Follow Step 11 to bring up the Add Reference dialog box again.
Switch to the .NET tab.
Select System.ComponentModel.DataAnnotations and System.Windows.Controls.Data, and then click OK.
At this point, the project should compile successfully. On the Build menu, click Build Solution.
Task 3: Building the application
In this task, you will write code in the project to be able to consume the Tag data from the server (other data requires that a user id to be specified as a filter).
1.In the Solution Explorer, expand MainPage.xaml and double-click MainPage.xaml.cs to open the file.
At the beginning of the file, add the following statements.
using DefaultScope; using Microsoft.Synchronization.ClientServices.IsolatedStorage;
Inside the MainPage class, create a new variable of type DefaultScopeOfflineContext and name it context
DefaultScopeOfflineContext context;
In the constructor of the MainPage class, add a line of code to create the context above the InitializeComponent method call.
context = new DefaultScopeOfflineContext("list_client", new Uri(new Uri(new WebClient().BaseAddress), "../DefaultScopeSyncService.svc/"));
The first parameter is the relative directory within isolated storage where the offline data should be cached. The second parameter specifies the address of the service. Example: http://localhost:65338/DefaultScopeSyncService.svc.
As the scope on the server is filtered by user id, we must specify the parameter here as described in the following list.
Add the following line of code to the constructor of MainPage class above the InitializeComponent statement.
context.CacheController.ControllerBehavior.AddScopeParameters("userid", new Guid("{EE9F0661-AD72-4b0b-8627-73722520A41B}").ToString());
On the Tools menu, click Create Guid.
Select the Registry Format radio button and then click Copy and then click Exit
Paste the GUID in the clipboard to replace the GUID in the above AddScopeParameters method call.
Important
The tag data is not filtered by user id. Therefore, the GUID we pass here does not matter. For other tables in the database, the user id must match one in the User table.
Now we need to display the data. In the Solution Explorer, double-click on MainPage.xaml in the ListClient project.
Add two rows to the LayoutRoot grid: Add the following lines of code in between <Grid x:Name="LayoutRoot"> and </Grid>.
<Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>
In the first row, you will place a DataGrid that displays the tags. In the second row, you will place a button to start synchronization.
Expand the Toolbox tab and drag a DataGrid into the XML markup. Make sure that it is after Grid.RowDefinitions closing tag, but before the Grid closing tag. Then follow these steps for the data grid.
- Add an xml property of x:Name to the DataGrid element and make the value TagsGrid.
- Set its Grid.Row property to 0.
- c.Set IsReadOnly to False because we want to be able to modify the tags.
After this, the data grid should be specified as follows (also removing the closing tag and changing the initial tag to end in “/>”:
<data:DataGrid x:Name="TagsGrid" Grid.Row="0" IsReadOnly="False" />
Important
If you are typing in the DataGrid specification by hand, you also have to add the namespace for the DataGrid to the top-level UserControl declaration (dragging from the Toolbox does this automatically). The namespace is as follows:
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Add a Button to the MainPage.xaml file after the DataGrid, specified as follows:
<Button Content="Sync" Grid.Row="1" HorizontalAlignment="Center"/>
Add an event handler for the button. In order to do so, place the cursor before the end of the tag and type Click=. At this point Visual Studio should display a dropdown. Hit the TAB button to auto-generate a new event handler. Your button specification should look as follows:
<Button Content="Sync" Click="Button_Click" Grid.Row="1" HorizontalAlignment="Center"/>
Now the editing of the XAML is complete and we are ready to write the code. The XAML file should look as follows:
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="ListClient.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> <Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <data:DataGrid x:Name="TagsGrid" Grid.Row="0" IsReadOnly="False" /> <Button Content="Sync" Click="Button_Click" Grid.Row="1" HorizontalAlignment="Center"/> </Grid> </UserControl>
Return to the MainPage.xaml.cs page
In the constructor, add an event handler for the DefaultScopeOfflineContext.LoadCompleted event in the line after you assign the context variable:
context.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(context_LoadCompleted);
Following that line, add an event handler for the MainPage.Loaded event:
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
Your MainPage constructor should now look as follows:
public MainPage() { context = new DefaultScopeOfflineContext("list_client", new Uri(new Uri(new WebClient().BaseAddress), "../DefaultScopeSyncService.svc/")); context.CacheController.ControllerBehavior.AddScopeParameters("userid", new Guid("{EE9F0661-AD72-4b0b-8627-73722520A41B}").ToString()); context.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(context_LoadCompleted); this.Loaded += new RoutedEventHandler(MainPage_Loaded); InitializeComponent(); }
Following the MainPage constructor, create the MainPage_Loaded method (if it wasn’t generated by Visual Studio) to handle the MainPage.Loaded event.
In this method, load the context. This is so that we can put the data into the DataGrid. Since we are loading on startup, we don’t want it to block the UI. Therefore, we call the DefaultScopeOfflineContext.LoadAsync method. The MainPage_Loaded method should look as follows.
void MainPage_Loaded(object sender, RoutedEventArgs e) { context.LoadAsync(); }
We then implement the context_LoadCompleted event, which will be responsible for getting the data from the context and assigning it to the DataGrid. This is accomplished rather simply, by getting the desired collection from the context, in our case Tags, and assigning it to the ItemsSource property of Data Grid.
One important note about doing this is that the context_LoadCompleted event may be called on a thread that is not the UI thread, which will cause an exception if we try to modify a UI element. As a result, you must use the Dispatcher.BeginInvoke to make sure that the work is done on the UI thread. Because of the simplicity of the code for this, we will use an anonymous delegate to update the data. The code for the method is as follows:
void context_LoadCompleted(object sender, LoadCompletedEventArgs e) { Dispatcher.BeginInvoke(delegate { TagsGrid.ItemsSource = context.TagCollection; }); }
Add the following two statements to the Button_Click method. The first statement saves any changes you made in the data grid and the second statement initiates the synchronization process.
// saves any outstanding changes made by the application context.SaveChanges(); // refreshes the cache by uploading all modified changes and then by downloading the server changes context.CacheController.RefreshAsync();
At this point, the code for the application is complete. The MainPage.xaml.cs file should look as follows:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using DefaultScope; using Microsoft.Synchronization.ClientServices.IsolatedStorage; namespace ListClient { public partial class MainPage : UserControl { DefaultScopeOfflineContext context; public MainPage() { // create an instance of offline context type // the code for this class is generated by the // SyncSvcUtil utility. context = new DefaultScopeOfflineContext("list_client", new Uri(new Uri(new WebClient().BaseAddress), "../DefaultScopeSyncService.svc/")); // specify a value for the userid parameter for scope context.CacheController.ControllerBehavior.AddScopeParameters( "userid", new Guid("{832106DC-2532-4f7a-9E6D-050383957D38}").ToString()); // subscribe for the context.LoadCompleted event context.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(context_LoadCompleted); // subscribe for the Page.Loaded event this.Loaded += new RoutedEventHandler(MainPage_Loaded); // subscribe for the RefreshCompleted event context.CacheController.RefreshCompleted += (sender, args) => { if (args.Error != null) { Dispatcher.BeginInvoke( delegate { // display any error occurred during // refresh operation in a message box MessageBox.Show(args.Error.ToString()); }); } }; InitializeComponent(); } void MainPage_Loaded(object sender, RoutedEventArgs e) { // when the page is loaded, invoke LoadAsync on the // context object to load data from the cache // into memory asynchronously. // This method raises the LoadCompleted event at // the end of load operation. context.LoadAsync(); } void context_LoadCompleted(object sender, LoadCompletedEventArgs e) { // bind the TagCollection object of context to // ItemsSource property of TagsGrid Dispatcher.BeginInvoke(delegate { TagsGrid.ItemsSource = context.TagCollection; }); } private void Button_Click(object sender, RoutedEventArgs e) { // saves any outstanding changes made by the application context.SaveChanges(); // refreshes the cache by uploading all modified changes and // then by downloading the server changes context.CacheController.RefreshAsync(); } } }
From the
Build
menu, click
Build Solution
to the build the solution.
Make sure that the
ListService
project is set as the
Startup project
for the solution.
In the Solution Explorer, right-click Solution ‘ListService’ (2 projects), and then click Set Startup Projects.
Confirm that Single startup project option is selected and the ListService is specified as the startup project. If this is not the case, select the Single startup project option and select ListService project from the list.
Click OK to close the Solution ‘ListService’ Property Pages dialog box.
Important
If you do not set the ListService project as the startup project, you will see the following error when you perform the next step: “An unhandled exception (‘Unhandled Error in Silverlight Application Uri must be http or https schema Parameter name: serviceUri at ….”
In the
ListService
project, right-click
ListClientTestPage.html
, and then click
Set As Start Page.
Press
F5
or
Ctrl+F5
to run the code. You should see an Internet Explorer window that opens html page.
Now, click Sync to see something similar to the following:
If you click Sync button and no data appears, you can register an event handler to discover the error. One example is as follows (if you add these lines to the constructor):
context.CacheController.RefreshCompleted += (sender, args) => { if (args.Error != null) { Dispatcher.BeginInvoke( delegate { MessageBox.Show(args.Error.ToString()); }); } };
Optional Steps
- Add couple of rows to the Tag table in the listdb database and then click Sync to see the new data that you added to the table in the list.
- Delete a row you added in the earlier step and then click Sync to see that deleted row disappears from the list.
- Update a row you added in the first step and then click Sync to see that data is also updated in the list.
- Click on Mortgage in the list and change it to something else, and then click Sync. Confirm that the value is uploaded to the listdb SQL Server database by using SQL Server Management Studio.
Optional: Deploying Service to IIS
This optional walkthrough contains steps to host the sync service in IIS instead of hosting it in an ASP .NET Development Server, and use the service from a Silverlight client application.
Task 1: Hosting the service in IIS
You can use Visual Studio to host your service in IIS or you can host it directly using IIS Manager. The following procedure contains steps to host the service you created in IIS.
In the Solution Explorer, right-click the ListService project and choose Properties.
Choose the Web tab.
Select Use Local IIS Web server.
Optional: If you want to change the name of the Virtual Directory you can change the Project Url.
Click Create Virtual Directory.This should host your sync service in IIS.
Make sure that the application pool that hosts the virtual directory uses the 2.0 version of the .NET Framework. The following list provides steps to determine the application pool that the service uses.
- Launch IIS Manager.
- Expand <computer name>, Expand Sites, expand the site that hosts the service.
- Right-click the application that contains the service, point to Manage Application, and then click Advanced Settings.
- Note the name of the application pool under General settings.
- Click Cancel to close the Advanced Settings dialog box.
Make sure that the application pool uses .NET Framework 2.0. The following list describes steps to configure the application pool that the sync service belongs to use .NET Framework 2.0.
- Launch IIS Manager.
- Expand <computer name>, click Application Pools.
- Right-click DefaultAppPool, and then click Basic Settings.
- Select v2.0.x.xxxxx for .NET Framework version.
- Click OK on the Edit Application Pool dialog box.
Make sure that the account under which application pool that the virtual directory uses has access to the listdb database. By default, the DefaultAppPool runs under the NetworkService account. Therefore, you have to make sure that this account has access to the SQL Server database. If you have this application pool running under a different account, make sure that the account has access to the SQL Server database. The following procedure provides steps to provide NetworkService account access to the SQL Server database.
- Launch SQL Server Management Studio.
- Expand Security, right-click Logins, and then click New Login.
- Enter NT AUTHORITY\NETWORK SERVICE for the Login name, switch to the User Mapping tab.
- Select listdb from the database list and select db_owner from the role list, and then click OK.
Task 2: Updating the Silverlight client to use the service hosted in IIS
In Visual Studio, expand ListClient project, expand MainPage.xaml, and then double-click Mainpage.xaml.cs to open the file in editor.
Modify the DefaultScopeOfflineContext constructor call to use list_client_2 as the name of local cache, and http://localhost/ListService/DefaultScopeSyncService.svc as the URI.
Note
A cache can be associated with a specific uri. The list_client cache was associated with the old URI. Therefore, you have to change both Uri and the cache name.
Right-click Solution ‘ListService’ (2 projects), and then click Build Solution to build the solution.
Switch to IIS Manager. In IIS Manager, expand <computer name>, expand Sites, expand Default Web Site, and then click ListService.
Switch to Content View in the middle pane.
right-click ListClientTestPage.html, and then click Browse.
Click Refresh to download all the tags from database to local cache.
Note
If you access the Silverlight application from a different host than the service, your service must have a clientaccesspolicy.xml file at the root of the service in order to allow cross-domain calls. Here is a sample 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>
Optional steps
- Add a couple of rows to the Tag table in the listdb database and then click Refresh to see the new data that you added to the table in the list.
- Delete a row you added in the earlier step and then click Refresh to see that deleted row disappears from the list.
- Update a row you added in the first step and then click Refresh to see that data is also updated in the list.
Troubleshooting the Tutorial
his topic contains troubleshooting information for the tutorial.
You receive unhandled exception regarding Uri when you run the code
If you do not have the ListService project as the startup project in the solution, you will receive the following error message:
“An unhandled exception (‘Unhandled Error in Silverlight Application Uri must be http or https schema Parameter name: serviceUri at Microsoft.Synchronization.ClientServices.CacheController..ctor(Uri serviceUri, String scopeName, OfflineSyncProvider localProvider)”
To resolve this issue, set the ListService project as the startup project by using the following steps and run the code again by pressing F5 or Ctrl+F5.
- In the Solution Explorer, right-click Solution ‘ListService’ (2 projects), and then click Set Startup Projects.
- Select the Single startup project option and select ListService project from the list.
- Click OK to close the Solution ‘ListService’ Property Pages dialog box.
- Press F5 or Ctrl+F5 to run the code again.
How to pass exception information to the client in the HTTP response?
Exception information (message + stack trace) can be returned as a response back to the caller. This is helpful during development to debug errors due to configuration of service/SQL Server and so on Verbose errors are disabled by default. To enable this add the following line to the InitializeService method of the service
config.UseVerboseErrors = true;
Caution
Do not deploy to production with this property set to true. Doing so would pass on exception stack trace information to clients which may not be desirable.
Can I make concurrent sync requests from the same client?
As of now, the service does not support concurrent requests from the same client that has batching enabled.
How can I use the Merge Conflict Resolution policy
You can use the business logic extensibility feature, especially a conflict interceptor method, to implement a merge resolution. This method has an out parameter, which is a merged version. When merge resolution is desired, the conflict interceptor method should return SyncConflictResolution.Merge and also set the output parameter to the merged entity
I set my download batch size to 50KB but I see that the response content length is more than 50KB. Why?
The batch size indicates how much data is to be batched per call. The serialization format that you select ([[OData]]:Atom or OData:JSON) will add to the content length.
I created a service by using Visual Studio 2008 and I have .NET 4.0 installed on my computer. My service does not run correctly. What may be wrong?
If you have .NET Framework 4.0 installed on your computer and you created a service by using Visual Studio 2008, we recommend that you to make sure that your application pool is configured to run under .NET Framework 2.0. This may fix your issue.
The following list provides steps to determine the application pool that the service uses.
- Launch IIS Manager.
- Expand <computer name>, Expand Sites, expand the site that hosts the service.
- Right-click the application that contains the service, point to Manage Application, and then click Advanced Settings.
- Note the name of the application pool under General settings.
- Click Cancel to close the Advanced Settings dialog box.
The following list describes steps to configure the application pool that the sync service belongs to use .NET Framework 2.0.
- Launch IIS Manager.
- Expand <computer name>, click Application Pools.
- Right-click DefaultAppPool, and then click Basic Settings.
- Select v2.0.x.xxxxx for .NET Framework version.
- Click OK on the Edit Application Pool dialog box.
I read the connection string to my SQL server from the Web.config. Why does the service not pick the value when I change the value in the Web.config?
The InitializeService method which initialized the service configuration is called only once for the lifetime of the service. You would have to recycle the application pool for the service to detect this change.
How can I configure IIS and SQL Server so that the IIS service account has access to the sample database?
- Modify IIS to use NetworkService account, or any account which has access to SQL.
- Launch IIS Manager.
- Click Application Pools, right-click DefaultAppPool, and then click Advanced Settings.
- Change Process Model/Identity to Network Service.
- Grant the Network Service account access to the sample database. The following list contains the steps to do this:
- Launch SQL Server Management Studio.
- Expand Security, right-click Logins, and then click New Login.
- Enter NT AUTHORITY\NETWORK SERVICE for the Login name, switch to the User Mapping tab.
- Select listdb from the database list and select db_owner from the role list, and then click OK.
The SQLCmd.exe does not seem to work
Make sure the SqlCmd.exe corresponds to the one in location “C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE”.
Tutorial does not work with a named SQL Server instance
The listdbconfig.xml file is configured to use with the default instance of SQL Server. If you have a named instance, open the listdbconfig.xml and modify the value of DBServer attribute of the TargetDatabase element.
For example, if your SQL Server instance is named MYSQLINSTANCE, replace DbServer=”.” with DbServer=”.\MYSQLINSTANCE”, the TargetDatabase element would look like:
If you are using named SQL Server instance, in the connection string in the service code, make sure that you specify the instance name. For example: if your SQL Server instance is named MYSQLINSTANCE, replace (local) with .\MYSQLINSTANCE.
I see an empty list after clicking the Sync button
If no data appears in the list after you press Sync button, add the following RefreshCompleted handler code to display any error occurred during the refresh operation. Add this handler code to the construction of the MainPage class.
context.CacheController.RefreshCompleted += (sender, args) => { if (args.Error != null) { Dispatcher.BeginInvoke( delegate { MessageBox.Show(args.Error.ToString()); }); } };
You receive a DbSyncException exception when you click Sync button
If a cache controller that was created during the previous execution of tutorial/sample still exists, you may see the following exception when you click Sync button.
Microsoft.Synchronization.Data.DbSyncException
Cannot find a valid scope with the name 'defaultscope_' in table '[scope_info]'. Ensure that this scope exists and that it has a corresponding valid configuration in the configuration table '[scope_config]'. at Microsoft.Synchronization.Data.SqlServer.SqlProviderFactory.ReadConfiguration(String scopeName, SyncSchemaInfo syncSchemaInfo)To resolve this issue, follow these steps:
- Navigate to the ListClientTestPage in a Web browser, right-click in the Web browser, and then click Silverlight to launch Microsoft Silverlight Configuration dialog box.
- Switch to the Application Storage tab.
- Click Delete All or select a Web site and then click Delete to delete the storage specific to an application (example: http://localhost:65338).
Diagnostics Page displays UNKNOWN ERROR as status for Sync Framework Runtime
If you see the status of Sync Framework runtime as "UNKNOWN ERROR" on the diagnostics page, it is most likely that your service is running under x64 mode on IIS and you have installed x86 SDK framework . Make the following changes and try accessing the page again.
Configure the application pool under which the service is running to allow 32-bit applications to run.
- Launch IIS Manager.
- Right-click the application in which the service exists (ListService), point to Manage Application, and then click Advanced Settings.
- Note the value for Application Pool setting and close the dialog box.
- Click Application Pools in the tree view.
- Right-click on the application pool that the service is using, and then click Advanced Settings.
- Change the value of Enable 32-bit Applications property to True, and close the dialog box.
- Right-click the application pool, and then click Recycle.
- Try accessing the diagnostic dashboard again.