Use WPF and WCF to Build Next-generation Applications

n the previous articles in this series you took a look at how to use the Microsoft Expression Interactive Designer to separate the design from the underlying implementation of your applications. Expression is a next-generation tool, aimed at designers, that allows them to create rich, interactive clients that run using XML Application Markup Language (XAML) technology.

XAML is an important evolutionary step in application design, allowing, among other things, the clean separation of application design from implementation, and more importantly, letting designers and developers share the same technology base. I (and you’ve probably experienced this too) have worked on many projects where businesspeople work with designers who build elaborate front-end mockups in various designer-focused formats, such as Flash or Photoshop. Later, the project developers had to emulate those mockups using different tools and formats, such as Visual Studio.NET or Java.

The problem is that there’s always an impedance mismatch between such disparate tools, which inevitably leads to designer-developer conflict.

Now, with Expression, designers have collaborative (if not familiar) tools with which to create their beautiful designs, outputting them directly as XAML, or as Visual Studio Projects. The implementers (developers) can use that output directly to build the back end functionality of the application, bypassing the need to re-create the UI from a mockup.

Additionally, using the Windows Communication Foundation, developers can build the back end to use secure, transactable, and reliable constructs that provide a true service orientation.

You saw the designer’s side of this process in the article “Take Avalon to the Next Dimension to Achieve 3D Effects.” In this article, you’ll look at the process from the developer’s side of the fence. It’s important to note that?now that developers and designers can use the same files?the designer/developer collaboration can work both ways. In this article, you’ll see how to build a service using the Windows Communication Foundation, and create a test client for it using “Cider,” the plug-in for Visual Studio.NET that allows you to build XAML interfaces. Just as a design-first project forms the input for developers, this functionality-first project will form a prototype that you could then pass to a designer, who would use the object names and event mappings from this project to build the final UI.

Before You Start
First, I strongly recommend that you uninstall everything to do with WinFX, the Windows SDK and any other development betaware before you begin. Indeed, I think it is a good idea to even remove Visual Studio 2005 and the .NET framework 2 before beginning. You can try it with these pre-installed, but I have obtained the best results by starting with a completely clean machine. You might try all this out using a virtual machine image running in either Microsoft Virtual PC or VMWare Workstation.

Second, before you begin, you should download, install and run the terrific ‘cleaner’ utility from CCleaner.com. This tool plows through your registry looking for bad, old, or corrupt keys (the usual side effect of using betaware), and cleans them out. To get started with WPF, I followed this process, and everything worked cleanly, first time.

When you are ready, you should download and install this software in this order:

  1. First, you’ll need SQL Server 2005 and the AdventureWorks sample database. If you don’t have this already, there’s a trial version available.
  2. Next, you’ll need the WinFX runtime components.
  3. After installing these, reboot?and if you don’t have it already, you can install Visual Studio 2005. If you don’t have a copy of this, you can use the free Express Edition.
  4. Next, download the Windows SDK?a huge download of about 1GB. Note that with the SDK, one option is to download the IMG file and burn it to a DVD or load it into a virtual CD/DVD application and install it from there. Unfortunately, when I did this, the installation failed every time. So instead, I recommend that you download the IMG, and then download the associated Setup.exe (you’ll find that download on the same page). Put both of these in a directory on your hard drive. Run the Setup.exe application and it will read the IMG file for you; then you can install successfully.
  5. Next, you must install the Visual Studio development tools (codenamed ‘Orcas’) for WinFX development. These include the ‘Cider’ designer for XAML in Visual Studio.

If you’ve gotten this far, you’re now ready to start coding WPF applications, but one final download (and one well worth your time) is the Expression Designer for XAML.

As a developer, you can use Cider to build basic XAML user interfaces within Visual Studio.NET, in a manner that you will be very familiar with, as it is virtually identical to the basic Windows forms designer, though a little rough around the edges.

To follow the flow of this article and start using some of the really slick features that XAML offers, I recommend that you explore the Expression Designer for XAML.

Building the Service Layer
After following the installation procedures, you now have a development environment that allows you to build next-generation Windows and Web applications?congratulations! So, let’s get started.

To build a new WinFX service, use the File->New Web Site command in Visual Studio.NET. If you have the new environment set up correctly, your dialog will look that in Figure 1.

Figure 1. Create a new WinFX service.

You’ll see that there is a new template called ‘WinFX’ service. Selecting this template creates a solution containing everything needed for a Windows Communication Foundation service. You can find the finished service in the download.

This service wraps the underlying database in a WCF layer. Achieving this is very simple.

First, add a new DataSet to the project, and then add two simple queries. The first query selects the full details for a specific record, including details from both the Product table and the ProductPhotos table. The SQL to get this data looks like this:

SELECT        Production.Product.ProductID,    Production.Product.Name,    Production.Product.ProductNumber,    Production.Product.ListPrice,    Production.Product.Color,    Production.Product.Size,    Production.Product.Style,    Production.ProductPhoto.ThumbNailPhoto,    Production.ProductPhoto.LargePhotoFROM            Production.Product INNER JOIN   Production.ProductProductPhoto ON    Production.Product.ProductID =      Production.ProductProductPhoto.ProductID INNER JOIN   Production.ProductPhoto ON    Production.ProductProductPhoto.ProductPhotoID =    Production.ProductPhoto.ProductPhotoIDWHERE        (Production.Product.ProductID = @MyID)

The query takes one parameter, @MyID, which the service passes to it.

The second query returns a subset of data for all the records in the database. To keep it simple, I’ve restricted the query so it includes only records where the price exceeds a certain amount, as the database is very large.

SELECT        ProductID, NameFROM            Production.ProductWHERE        (ListPrice > 100)

The service that exposes this information provides the following operation contracts, as defined by WCF:

[OperationContract]   string GetProductDescription(int nID);[OperationContract]   recordDetails[] GetAllRecordDetails();[OperationContract]   fullRecord GetFullRecordDetails(int nID);

GetProductDescription returns the name of the product with the specified ID.

GetAllRecordDetails returns an array (of type recordDetails) containing the product ID and the name for each product in the database.

GetFullRecordDetails returns an object of type fullRecord for a product specified by its ID.

Figure 2. View the WCF service.

These operation contracts require some data contracts to define the data types being passed across the wire. These are called recordDetails and fullRecord. You can see the DataContracts that define them here.

[DataContract()]public class recordDetails{    [DataMember]    public int nID;    [DataMember]    public string strName;}[DataContract()]public class fullRecord{    [DataMember]    public int nID;    [DataMember]    public string strName;    [DataMember]    public string strProductNumber;    [DataMember]    public Decimal nListPrice;    [DataMember]    public string strColor;    [DataMember]    public string strSize;    [DataMember]    public string strStyle;    [DataMember]    public byte[] bThumbNailPhoto;    [DataMember]    public byte[] bLargePhoto;}

After setting these contracts up, it’s pretty straightforward to write C# code that queries the database based on the input parameters and returns the appropriate values. You can see the implementation of each operation contract in the download. As an example, here’s how the GetAllRecordDetails operation is implemented.

public recordDetails[] GetAllRecordDetails(){   AWProductTableAdapters.ProductTableAdapter da = new      AWProductTableAdapters.ProductTableAdapter();   AWProduct.ProductDataTable dt = da.GetData();   recordDetails[] recs = new       recordDetails[dt.Rows.Count];   int n = 0;   foreach (AWProduct.ProductRow row in dt.Rows)   {      recordDetails rd = new recordDetails();      rd.nID = row.ProductID;      rd.strName = row.Name;      recs[n] = rd;      n++;   }   return recs;}

If the service is implemented correctly, when you compile and run it you’ll see a result like that in Figure 2, by browsing to Service.svc on the implementation Web.

Author’s Note: Copy the WSDL URI at the top of the Web service test screen. You’ll need it in the next step.

Creating the Service Proxy
To communicate with this service, your Avalon client will use a service proxy. This proxy needs to be generated based on the WSDL of the service. If you browse to the Service.svc file in the Web site, you’ll see the address of the WSDL at the top of the screen (see Figure 2).

Generating a proxy is very straightforward use the svcutil.exe tool that comes as part of the WinFX SDK. You can find this tool in the C:Program FilesMicrosoft SDKsWindowsv1.0Bin directory. It’s a good idea to add that to your path.

When you run svcutil.exe, passing it the WSDL URI as a parameter, it generates two files.

The first is called output.config. This contains the configuration information needed by the service model (the heart of WCF) to set up the communications pipeline. You should copy and paste the content of this file into your App.config file. Here’s what it looks like:

                                                                                                                      

The preceding XML configures the node, setting up a binding?this is how WCF creates the communications channel. It also configures the client communication, defining which binding it should use, and the underlying endpoint for the service that it will talk to.

The second file that svcutil.exe creates is called output.cs, which is the proxy implementation. This manages all the communication on your behalf. You simply create an instance of it in your client and call the operation contracts it exposes as local methods. If you’re familiar with consuming Web services in C#, this works in exactly the same way.

Building the Client
In a real-world scenario, a designer will have used the Microsoft Expression Interactive designer to put together a prototype of the front end, and will have handed you the C# project, or the XAML (or both) for you to plug it into the back end. But in this article, and for brevity’s sake, I’m just going to use a simple XAML front-end built using the Cider add-on to Visual Studio to emulate the designer’s portion of the process.

To create a WPF client in Visual Studio.NET, select the WinFX application project type (see Figure 3). You can either use the version in the download for this article, or if you want to try it yourself, add a new project to your solution, and select ‘WinFX Windows Application’ as the project type.

You’ll use the “Cider” XAML designer for Visual Studio.NET to build the WinFX Windows Application (see Figure 4).


Figure 3. Create a WinFX Windows application.
?
Figure 4. Using the “Cider” XAML Designer.

For this example, I designed a XAML UI containing a list box, several labels, and an image control. The underlying XAML for this is in Listing 1.

One little bug in Cider is that after you initially place and name a control in the application, it isn’t immediately available to Intellisense in the code window. But if you save your application and rebuild it, presto! It turns up!

Another little gotcha (remember this is betaware) is that there’s no straightforward way to map event handlers to controls. This example calls for an action to happen when you select an item on the ListBox, but you can’t simply double-click on the control as you normally can to insert an event-handler, or select an event from the Properties window; instead, you have to hand-code the event-handler in the XAML. It looks like this:

To build the content of the List box, you use the proxy to call the service to get all record details. Here’s the code, which is called upon Window Initialization. In the top element in the XAML in Listing 1, you’ll see the Loaded=”InitEverything” attribute. This code is present in that function:

using (AdwServiceProxy proxy =  new AdwServiceProxy("default")){  recs = proxy.GetAllRecordDetails();  for (int nIndex = 0; nIndex < recs.Length; nIndex++)  {    string strText = recs[nIndex].strName;    lstBox1.Items.Add(strText);  }}

The preceding code uses the AdwServiceProxy proxy instance to get the details and then parses the returned array into ListItems that get added to the ListBox.

When you select an item from the ListBox, you can then pull its ID, and use that to get additional record details (including the picture) using a Web service call to populate the image box and labels:

private void HandleListClick(object sender,    SelectionChangedEventArgs e){   using (AdwServiceProxy proxy =      new AdwServiceProxy("default"))   {      int nID = recs[lstBox1.SelectedIndex].nID;      fullRecord theRecord =          proxy.GetFullRecordDetails(nID);      BitmapImage myBitmapImage = new BitmapImage();      myBitmapImage.BeginInit();      myBitmapImage.StreamSource = new           System.IO.MemoryStream(         theRecord.bLargePhoto);      myBitmapImage.EndInit();      imgProduct.Source = myBitmapImage;      lblName.Content = theRecord.strName;      lblColor.Content = "Color : " +          theRecord.strColor;      lblPrice.Content = "Cost : " +          String.Format("{0:C}", theRecord.nListPrice);      lblProductNumber.Content = "Product Number : " +           theRecord.strProductNumber;      lblSize.Content = "Size : " + theRecord.strSize;                   }}

Now, when you run the application you'll see something similar to Figure 5.

Figure 5. Run your test client in Avalon.

In this article you stepped through the full end-to-end process, from data through presentation, for building a multiple tier article using the next-generation Windows development technologies. You built a WCF service that wraps the database, exposing the required operation contracts. You then built a proxy to this underlying service using the Windows SDK tools, and used this proxy in a simple Avalon client, created with Cider.

If you like, you could enhance this client using Microsoft Expression Interactive designer, adding 3D, Gel, Mirroring, animation and other effects. For more information on these, check out the previous articles in this series.

It's a fun and exciting time to be a Windows developer, and with this unprecedented level of early access to the SDKs and development methodology, now is a terrific time to sharpen your toolbox using the betas!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: