Hands-On Lab
Windows Phone 7 & The Cloud
Lab version: 1.0.0
Last updated: 11/29/2011
Contents
Overview 3
Exercise 1: Connecting Windows Phone 7 with WCF Data Services 8
Task 1 – Exposing an Entity Framework Model Using WCF Data Services 8
Task 2 – Creating WP7 Client Consuming WCF Data Services 14
Summary 44
Overview
This hands-on lab introduces you to the tools and the steps required to build a small Silverlight Windows Phone 7 application that consumes a WCF Data Services from an application hosted in Windows Azure.
WCF Data Services enables you to expose and consume data from different devices and infrastructures leveraging the Open Data Protocol (OData). OData is a protocol that allows you to expose your data as resources that are addressable by URIs. This enablesyou to use the semantics of representational state transfer (REST) for accessing the exposed data. The standard HTTP verbs of GET, PUT, POST, and DELETE are supported by it.
In this hands-on lab, you will be creating a simplified version of the MyTODO sample; first, you will expose its entity model through a WCF Data Service, which will then be consumed by the Windows Phone 7 Client. MyTODO is a Microsoft Developer & Platform Evangelism sample application built on Windows Azure to manage and share simple lists (e.g. tasks to complete, favorite movies, books you enjoyed, etc.).
If you want to explore a complete version of the myTODO sample application, you can download it from http://code.msdn.microsoft.com/mytodo.
Objectives
In this hands-on lab, you will learn how to:
· Expose an Entity Framework model using WCF Data Services
· Create a Windows Phone 7 Client that consumes WCF Data Services
Prerequisites
The following is required to complete this hands-on lab:
· IIS 7 (with ASP.NET, WCF HTTP Activation)
· Microsoft .NET Framework 4.0
· Microsoft Visual Studio 2010
· Windows Azure Tools for Microsoft Visual Studio 1.6
· Windows Phone 7 SDK
Setup
For convenience, much of the code used in this hands-on lab is available as Visual Studio code snippets. To check the prerequisites of the lab and install the code snippets:
Note: Make sure you have checked all the dependencies for this lab before running the setup.
1. In order to allow the solution to connect with the database using SQL Server credentials, open SQL Server Management Studio and connect to the local SQL Server (i.e. .\sqlexpress).
2. Right click the server node and select Properties.
3. Select Security and make sure SQL Server and Windows Authentication mode is selected.
Figure 1
SQL Server Properties - Security
4. Click OK.
5. Restart the SQL Server instance to allow the previous configuration change to take effect.
Figure 2
Restart SQL Server
6. Open a Windows Explorer window and browse to the lab’s Source folder.
7. Double-click the Setup.cmd file in this folder to launch the set up process that will configure your environment and install the Visual Studio code snippets for this lab.
8. If the User Account Control dialog is shown, confirm the action to proceed.
Using the Code Snippets
Throughout the lab document, you will be instructed to insert code blocks. For your convenience, most of that code is provided as Visual Studio Code Snippets, which you can use from within Visual Studio 2010 to avoid having to add it manually.
If you are not familiar with the Visual Studio Code Snippets, and want to learn how to use them, you can refer to the Setup.docx document in the Assets folder of the training kit, which contains a section describing how to use them.
Exercises
This hands-on lab includes the following exercises:
1. Connecting Windows Phone 7 with WCF Data Services.
Estimated time to complete this lab: 30 minutes.
Note: When you first start Visual Studio, you must select one of the predefined settings collections. Every predefined collection is designed to match a particular development style and determines window layouts, editor behavior, IntelliSense code snippets, and dialog box options. The procedures in this lab describe the actions necessary to accomplish a given task in Visual Studio when using the General Development Settings collection. If you choose a different settings collection for your development environment, there may be differences in these procedures that you need to take into account.
Exercise 1: Connecting Windows Phone 7 with WCF Data Services
In this exercise, you will start with a simplified version of MyTODO and go through the steps of adding a WCF Data Service to expose its entity model, and then create a Windows Phone 7 client application that consumes it.
Task 1 – Exposing an Entity Framework Model Using WCF Data Services
In this task, you will create a WCF Data Service to expose MyTODO’s entity model and host it in the Cloud.
1. Open Visual Studio 2010 as an administrator. Go to the File | Open | Project menu and select Begin.sln located in the Source\Ex01-Connectivity\Begin folder of the lab.
2. Press F5 to run the application. Log on to the application and try the different options: creating a task list, adding tasks, marking a task as completed.
3. Close the browser and go back to Visual Studio.
4. Add a WCF Data Service class named MyTodoDataService to the MyTodo.Web project.
Figure 3
Adding a WCF Data Service
5. In the newly created MyTodoDataService class, insert the following namespace directives following the existing directives at the top of the file.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 UsingDataService - C#)
C#
using System.Diagnostics;
using System.Linq.Expressions;
using System.Security.Principal;
using System.ServiceModel;
using Microsoft.Samples.MyTodo.Web.Models;
using System.Web.Security;
using System.ServiceModel.Activation;
6. In the class definition, replace the placeholder labeled /* TODO: put your data source class name here */ with the name MyTodoEntities.
7. Add the following attributes to MyTodoDataService class.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 Attributes - C#)
C#
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
8. Locate the InitializeService method, and replace its code with the following, this will expose the TaskLists and Task entities to everyone consuming the service, later on this task, we will add the logic to only return the public Tasks.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 InitializeService - C#)
C#
config.SetEntitySetAccessRule("TaskLists", EntitySetRights.All);
config.SetEntitySetAccessRule("Tasks", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.UseVerboseErrors = true;
Figure 4
WCF Data Service Definition
9. Add a UserIdentity property, which will be used to identify the user that is consuming the service and to validate if he has access to the resources, or not.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 UserIdentity - C#)
C#
private IIdentity UserIdentity
{
get
{
string ticketValue = null;
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
// from cookie
ticketValue = cookie.Value;
}
else if (HttpContext.Current.Request.Headers["AuthToken"] != null)
{
// from http header
ticketValue = HttpContext.Current.Request.Headers["AuthToken"];
}
if (!string.IsNullOrEmpty(ticketValue))
{
try
{
var ticket = FormsAuthentication.Decrypt(ticketValue);
if (ticket != null)
{
return new FormsIdentity(ticket);
}
}
catch
{
}
}
return null;
}
}
10. Add the code below to the service definition; these methods contain the logic to hide those entities which are not public or owned by the user consuming the service.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 ListViewEventHandlers - C#)
C#
[WebGet]
public IQueryableTaskList> GetPublicLists()
{
return this.CurrentDataSource.TaskLists
.Where(o => o.IsPublic == 1)
.OrderBy(o => o.Name);
}
[QueryInterceptor("Tasks")]
public ExpressionFuncTask, bool> QueryTasks()
{
if (this.UserIdentity == null)
{
return c => c.TaskList.IsPublic == 1;
}
else
{
return c => c.TaskList.UserName.Equals(this.UserIdentity.Name, StringComparison.OrdinalIgnoreCase);
}
}
[QueryInterceptor("TaskLists")]
public ExpressionFuncTaskList, bool> QueryTaskLists()
{
if (this.UserIdentity == null)
{
return c => c.IsPublic == 1;
}
else
{
return c => c.UserName.Equals(this.UserIdentity.Name, StringComparison.OrdinalIgnoreCase);
}
}
11. In order to verify the correct implementation of the WCF Data service, press F5 to run the application.
Figure 5
Running Application
12. In Internet Explorer, append /MyTodoDataService.svc to the URL, and press ENTER. The address should look like http://127.0.0.1:{port}/MyTodoDataService.svc.
Figure 6
Running Application
Task 2 – Creating WP7 Client Consuming WCF Data Services
In this task, you will go through the steps of creating a Windows Phone 7 client to consume the WCF Data Service created in the previous task.
1. Add New Project using the Silverlight for Windows Phone – Windows Phone Application template, named MyTodo.Phone.Online
2. Add reference to the OData Client Library for WP7 (System.Data.Services.Client) located in the folder Assets\libs.
3. Remove the file MainPage.xaml located into the root of the project since you will not need it.
4. Add New Folder named Model, and create a new class named TasksList inside it.
5. Replace the class definition with the following.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 TaskList - C#)
C#
namespace MyTodo.Phone.Online.Models
{
using System;
using System.Collections.ObjectModel;
using System.Data.Services.Common;
[DataServiceEntity]
[DataServiceKey("Id")]
public class TaskList
{
public TaskList()
{
this.Tasks = new CollectionTask>();
}
public Guid Id { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public byte IsPublic { get; set; }
public CollectionTask> Tasks { get; set; }
}
}
6. Inside the Models folder, add another class, named Task, and replace its implementation with the following.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 Task - C#)
C#
namespace MyTodo.Phone.Online.Models
{
using System;
using System.Data.Services.Common;
[DataServiceEntity]
[DataServiceKey("Id")]
public class Task
{
public Guid Id { get; set; }
public string UserName { get; set; }
public TaskList TaskList { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Status { get; set; }
public DateTime StartDate { get; set; }
public DateTime DueDate { get; set; }
public DateTime TimestampUpdate { get; set; }
}
}
7. Add a new folder named Services in the Project’s root folder.
8. Inside it, add an interface named ITodoService, and replace its definition with the following
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 ITodoService - C#)
C#
using System;
using System.Collections.Generic;
using MyTodo.Phone.Online.Models;
namespace MyTodo.Phone.Online.Services
{
public interface ITodoService
{
event EventHandler<ServiceExceptionArgs> ServiceException;
void GetLists(ActionIEnumerable<TaskList> callback);
void GetListAndTasks(Guid listId, Action<TaskList> callback);
void AddList(TaskList list, Action<TaskList> callback);
void AddTask(TaskList list, Task task, Action<Task> callback);
void DeleteTask(Task task, Action<Task> callback);
void UpdateTask(Task task, Action<Task> callback);
}
public class ServiceExceptionArgs : EventArgs
{
public Exception Exception { get; set; }
}
}
9. Add a class named OnlineTodoService in the Services folder, which will implement the ITodoService interface and contain the logic required to consume the OData service.
10. Add the following namespace directives below the ones added by the class template.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 OnlineTodoServiceNamespaces - C#)
C#
...
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Diagnostics;
using System.Linq;
using MyTodo.Phone.Online.Infrastructure;
using MyTodo.Phone.Online.Models;
11. Implement the ITodoService interface, to do this, type : ITodoService behind the OnlineTodoService class name, click on the contextual menu, and select Implement Interface ITodoService.
Figure 7
Implement ITodoService Interface
12. Add the following code to the beginning of the class definition, this code contains the logic to create the Context that will be used to consume the WCF Data Service, adding the AuthenticationToken to each requests.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 OnlineTodoServiceDeclarations- C#)
C#
public class OnlineTodoService : ITodoService
{
private readonly Uri serviceUri;
public OnlineTodoService(Uri serviceUri)
{
this.serviceUri = serviceUri;
}
private DataServiceContext GetContext()
{
var dataService = new DataServiceContext(serviceUri);
dataService.MergeOption = MergeOption.OverwriteChanges;
dataService.SendingRequest += (sender, args) =>
{
if (string.IsNullOrEmpty(App.AuthenticationToken))
{
throw new ArgumentNullException("AuthenticationToken", "The AuthenticationToken is not set.");
}
args.RequestHeaders["AuthToken"] = App.AuthenticationToken;
};
return dataService;
}
...
When using the implement interface option, all methods where added but with no actual implementation.
13. Replace the auto-generated code of GetLists method with the code required to invoke the WCF Data Service.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 OnlineTodoServiceGetLists - C#)
C#
public event EventHandler<ServiceExceptionArgs> ServiceException;
...
public void GetLists(ActionIEnumerableTaskList> callback)
{
var requestUri = new Uri(string.Format("{0}TaskLists?$orderby='Name asc'&$expand=Tasks", serviceUri), UriKind.Absolute);
var ctx = this.GetContext();
ctx.BeginExecute<TaskList>(
requestUri,
delegate(IAsyncResult asyncResult)
{
try
{
var result = ctx.EndExecute<TaskList>(asyncResult).ToArray();
Deployment.Current.Dispatcher.BeginInvoke(() => { callback(result); });
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (this.ServiceException != null)
{
this.ServiceException(this, new ServiceExceptionArgs { Exception = ex });
}
});
}
},
null);
}
...
Note: As you can see, the code generates the URI that asks for all the TaskLists to the service, ordered by Name (ascendant) and expanding its Tasks. For more information on the URI conventions used for OData services you can visit http://www.odata.org/developers/protocols/uri-conventions
14. Replace the auto-generated code of AddList method with the code required to invoke the WCF Data Service.
(Code Snippet – Windows Phone 7 and The Cloud - Ex01 OnlineTodoServiceAddList - C#)
C#
public void AddList(TaskList list, ActionTaskList> callback)
{
list.UserName = string.Empty;
var dataService = this.GetContext();
dataService.AddObject("TaskLists", list);
dataService.BeginSaveChanges(
delegate(IAsyncResult asyncResult)
{
try
{
var response = dataService.EndSaveChanges(asyncResult).First();
Deployment.Current.Dispatcher.BeginInvoke(() => { callback(asyncResult.AsyncState as TaskList); });
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (this.ServiceException != null)
{
this.ServiceException(this, new ServiceExceptionArgs { Exception = ex });
}
});
}
},
list
);
}
15. Add the IAuthentication and the Authentication files located in the Assets\Services folder into the Services folder of your WP7 project. These files will handle the authentication logic, which is not in the scope of this exercise.
16. Add a service reference to the Authentication service. To do this, right-click on the WP7 project and select Add service reference. Click on Discover, and wait until the AuthenticationService.svc appears. Select it and make sure that the Address is http://localhost:{port}/AuthenticationService.svc.