Estimated Time: 60 minutes
Windows Communication Foundation (WCF) provides an excellent framework for exchanging data across network boundaries. It can be used to exchange data using standards-based Web Service specifications such as Simple Object Access Protocol (SOAP), Web Service Description Language (WSDL) and WS-I* standards. Any development framework capable of supporting Web Service standards can be used to call a WCF service including non-.NET frameworks.
To create a WCF service you define the ABCs for the service including the Address, Binding and Contract. The Address defines the URI of the service that a client uses to talk with it. You can think of it as being similar to a phone number or street address. The Binding defines the protocol to use while talking with the service. WCF supports several different protocols such as HTTP, TCP, named pipes and more. Finally, the contract defines the service's Application Programming Interface (API) including the data it can send and receive. The contract includes service operation names, data types used, as well as additional details.
WCF is a key player in Silverlight applications that need to access and manipulate data. Although standard WCF service projects can be created a used with Silverlight, The Silverlight Tools for Visual Studio 2010 provides a Silverlight-Enabled WCF Service project template that can be used to create service classes. The template configures services to use binary message encoding combined with the HTTP protocol which provides excellent performance. A WCF service can be called directly from a Silverlight application using a proxy object that is typically created directly in Visual Studio.
In this lab you'll learn how to create a Silverlight-Enabled WCF Service and define operations. You'll also examine the default configuration for Silverlight-enabled services and create a proxy object that can be used to communicate with a service from a Silverlight client. A bonus exercise is also included that demonstrates how to debug WCF service calls using a tool called Fiddler. The user interface that you'll build throughout the lab is shown next:
In this exercise you'll create a new Silverlight Navigation Application and add a Silverlight-Enabled WCF Service to the Web project. You'll then add code into the service's operations to make calls to repository objects responsible for communicating with a database using Entity Framework 4.
The ADO.NET Entity Data Model template can be found in the Data section of the Add New Item dialog. Alternatively, you can use Visual Studio 2010's Search Installed Templates feature in the upper-right corner of the dialog window to search for the template as well.
The Silverlight-enabled WCF Service template is located in the Silverlight templates section that's available when adding new items into a project.
Although you can add code logic directly into WCF service methods (often referred to as "operations"), it's recommended that you rely on external classes to handle business rules, interact with data access frameworks, etc. Rather than adding data access code into the service operations you'll rely on a set of data classes named CustomerRepository and SalesOrderHeaderRepository to perform the work in this lab.
| Language | File Location |
|---|---|
| C# | WCFServices/Starting Point/C# |
| VB | WCFServices/Starting Point/VB |
These classes derive from a custom RepositoryBase class and contain functionality to perform different database operations.
ICustomerRepository _CustomerRepository = new CustomerRepository(); ISalesOrderHeaderRepository _OrderRepository = new SalesOrderHeaderRepository();
Dim _CustomerRepository As ICustomerRepository = New CustomerRepository() Dim _OrderRepository As ISalesOrderHeaderRepository = _ New SalesOrderHeaderRepository()
Although this code defines the repository class type to use in the CustomersService class, because each repository class implements an interface the type could be injected into the service at runtime. This is useful in situations where more loosely coupled code is needed.
| Method | Return Type | Parameters |
|---|---|---|
| GetCustomers | List of Customer | None |
| GetOrdersByCustomerID | List of SalesOrderHeader | Integer named customerID |
| UpdateSalesOrderHeader | OperationStatus | SalesOrderHeader named order |
return _CustomerRepository.GetCustomers();
return _CustomerRepository.GetCustomers(
In this exercise you'll create a WCF service proxy, add controls to a Silverlight user interface and add code to call the WCF service created in the previous exercise. Throughout the exercise you'll see how data from a Web Service can be accessed and bound to controls asynchronously. You'll also push changes made in the Silverlight client back to the WCF service so that data is updated in the database properly.
This exercise uses the DataForm control available in the Silverlight Toolkit. If you don't currently have the Silverlight Toolkit installed download and install it from http://silverlight.codeplex.com before continuing.
<endpoint address="http://localhost:37156/Services/CustomersService.svc"
binding="customBinding"
bindingConfiguration="CustomBinding_CustomersService"
contract="CustomersService.Proxies.CustomersService"
name="CustomBinding_CustomersService" />
When you move a Silverlight project XAP file between development, test and production servers you'll need to update the address attribute in ServiceReferences.ClientConfig before compiling the project so that it points to the correct WCF service URI. Alternatively, a proxy object can programmatically be assigned the URI to use which can be useful in more dynamic environments.
| Header Property |
|---|
| Order Date |
| Ship Method |
| Sub Total |
| Total Due |
| Header Value | Binding to Add |
|---|---|
| Order Date | Binding="{Binding OrderDate,StringFormat=d}" |
| Ship Method | Binding="{Binding ShipMethod}" |
| Sub Total | Binding="{Binding SubTotal,StringFormat=C}" |
| Total Due | Binding="{Binding TotalDue,StringFormat=C}" |
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
CustomersServiceClient _Proxy = new CustomersServiceClient();
Dim _Proxy as New CustomersServiceClient()
_Proxy.GetCustomersCompleted +=
(s, args) => CustomersComboBox.ItemsSource = args.Result;
_Proxy.GetOrdersByCustomerIDCompleted +=
(s, args) => OrdersDataGrid.ItemsSource = args.Result;
_Proxy.UpdateSalesOrderHeaderCompleted += (s,args) =>
{
//Check returned OperationStatus object for status
string errorMsg = (args.Result.Status) → "succeeded" : "failed";
MessageBox.Show("Update " + errorMsg);
};
_Proxy.GetCustomersAsync();
AddHandler _Proxy.GetCustomersCompleted, _
Sub(s, args) CustomersComboBox.ItemsSource = args.Result
AddHandler _Proxy.GetOrdersByCustomerIDCompleted, _
Sub(s, args) OrdersDataGrid.ItemsSource = args.Result
AddHandler _Proxy.UpdateSalesOrderHeaderCompleted, Sub(s,args)
'Check returned OperationStatus object for status
Dim errorMsg As String = If(args.Result.Status, "succeeded", "failed")
MessageBox.Show("Update " & errorMsg)
End Sub
_Proxy.GetCustomersAsync()
This code hooks proxy object events to event handlers to handle asynchronous calls to the WCF service. It then calls the GetCustomersAsync method to initiate the call to the WCF service.
int custID = ((Customer)CustomersComboBox.SelectedItem).CustomerID; _Proxy.GetOrdersByCustomerIDAsync(custID);
Dim custID As Integer = (CType(CustomersComboBox.SelectedItem, _ Customer)).CustomerID _Proxy.GetOrdersByCustomerIDAsync(custID)
As mentioned at the beginning of this exercise, the DataForm control is part of the Silverlight Toolkit which will need to be installed to complete this exercise. The Silverlight Toolkit is available at http://silverlight.codeplex.com.
| Attribute/Property | Value |
|---|---|
| Name | OrderDataForm |
| CurrentItem | {Binding Path=SelectedItem,ElementName=OrdersDataGrid} |
| AutoEdit | False |
| AutoCommit | False |
| CommandButtonsVisibility | Edit, Commit, Cancel |
An example of using the Properties window to modify the CurrentItem property is shown next (you can certainly type in the XAML as opposed to doing this visually). Binding a XAML element such as CurrentItem to another XAML element's property is referred to as element to element binding.
In this exercise the DataForm will be used to show all properties of the SalesOrderHeader object. In a real-life application you'd want to constrain the data shown by the DataForm control and eliminate any unnecessary fields that the user won't use.
If you need help with this step refer to the code in this lab's Completed folder. To handle the event you can type it into the XAML on the DataForm element and then navigate to the event handler or highlight the control in the designer, view the Properties window, click the lightning bolt icon at the top of the window and then double-click the event.
if (e.EditAction == DataFormEditAction.Commit)
{
var order = OrderDataForm.CurrentItem as SalesOrderHeader;
_Proxy.UpdateSalesOrderHeaderAsync(order);
}
If e.EditAction = DataFormEditAction.Commit Then
Dim order = CType(OrderDataForm.CurrentItem, SalesOrderHeader)
_Proxy.UpdateSalesOrderHeaderAsync(order)
End If
This code will be called when the user clicks the OK or Cancel buttons on the DataForm control while editing a SalesOrderHeader object.
The code only allows the current item being edited in the DataForm control to be saved and doesn't allow multiple items to be saved as a batch. The next lab covering WCF RIA Services will show a built-in way to track object changes and submit a batch of changed objects back to the server.
While performing the previous tasks you may have noticed that the Cancel button in the DataForm was disabled. In this exercise you'll implement the IEditableObject interface on a partial SalesOrderHeader class to enable cancel functionality within the DataForm control. This partial class will add additional functionality to the existing SalesOrderHeader class created by the proxy generation wizard used earlier in the lab.
The namespace matches the namespace of the SalesOrderHeader class created by the proxy generation wizard.
UsingWCFServices.WebServiceProxies
WebServiceProxies
The code that follows can be found in this lab's Completed folder if you'd prefer to cut and paste it into the class.
SalesOrderHeader _OriginalObject;
bool _Editing;
public void BeginEdit()
{
if (!_Editing)
{
_Editing = true;
_OriginalObject = this.MemberwiseClone() as SalesOrderHeader;
}
}
public void CancelEdit()
{
if (_Editing)
{
Comment = _OriginalObject.Comment;
ShipDate = _OriginalObject.ShipDate;
_Editing = false;
}
}
public void EndEdit()
{
if (_Editing)
{
_Editing = false;
_OriginalObject = null;
}
}
Private _OriginalObject As SalesOrderHeader Private _Editing As Boolean Public Sub BeginEdit() Implements IEditableObject.BeginEdit If Not _Editing Then _Editing = True _OriginalObject = TryCast(Me.MemberwiseClone(), SalesOrderHeader) End If End Sub Public Sub CancelEdit() Implements IEditableObject.CancelEdit If _Editing Then Comment = _OriginalObject.Comment ShipDate = _OriginalObject.ShipDate _Editing = False End If End Sub Public Sub EndEdit() Implements IEditableObject.EndEdit If _Editing Then _Editing = False _OriginalObject = Nothing End If End Sub
The code added into the CancelEdit method only resets the Comment and ShipDate properties if a user presses the cancel button in order to keep the code as short as possible. In a real-world application you would reset all of the properties on the object that the user can edit through the DataForm.
WCF services provide an excellent way to exchange data between a server and a Silverlight client. However, when using a Silverlight-Enabled WCF Service data is exchanged over the wire in a binary format making it difficult to debug when there's a problem with the messages being sent or received. In addition to issues associated with viewing binary data, how do you view messages sent over the wire in the first place to ensure they're being sent/received correctly? In this exercise you'll learn how to use a tool named Fiddler in conjunction with a WCF binary-encoded message inspector to debug Silverlight service calls.
WCF also provides built-in tracing capabilities that allow messages going into and out of a service to be logged and traced. Additional details about configuring WCF tracing can be found at http://msdn.microsoft.com/en-us/library/ms733025.aspx.
Fiddler is a free HTTP proxy tool that can be used to view request and response messages.
The WCF Binary-encoded Message Inspector is an extension to Fiddler that automatically deserializes binary-encoded messages into SOAP so that you can view them while using Fiddler.
Ensure the file is added into the root of the UsingWCFServices.Web project. Because the Silverlight application is served from localhost and you're now trying to call the WCF service using "localhost." (note the period after localhost), a cross-domain policy file is required for the service calls to work properly.
In this lab you created an Entity Framework 4 model and a WCF service containing multiple service operations. You also called the service using a proxy object generated using Visual Studio and added custom code to handle the asynchronous callbacks and bind data to controls. Finally, you implemented the IEditableObject interface on a partial class to edit cancel support to the DataForm control. The specific tasks completed are shown next:
Comments (0)