This is the 7th post in a series of “31 Days of Silverlight.”
Today I’m going to show how to create a simple WCF service, and consume it from a Silverlight application. Talking to data services is something you’re going to need to do quite often, which is why I’ve spent two consecutive posts talking about it.
Create your Silverlight application
I’m going to start from the beginning. First, we need to create a new Silverlight project. I’m naming mine JBWCFService.
We will then be prompted to create a web project to accompany our Silverlight project. I choose a Web Application Project from the dropdown.
Here is a view of what my solution explorer looks like after the projects are created. I have a Silverlight project called JBWCFService and a Web Application project called JBWCFServiceWeb, not surprisingly.
Create a data source
Next, I want to create a SQL database from which to get my data from. I’m not going to walk through all the steps of adding tables, columns, and data. You can certainly find that elsewhere. Here’s my adding the SQL database to my project though…
Create your service
OK, it’s time to create our service. I’m naming my service MyNewService. It’s just another thing to add to our project, so here we go:
Once the new service has been created, you will have a few new files in your project. In my case, they are named IMyNewService.cs, MyNewService.svc, and its code-behind, MyNewService.svc.cs. By default, the interface (IMyNewService.cs) will be open and ready for editing. They create a DoWork() method for you, but we’re going to delete that and do something more interesting in a little while. First, we need to get LINQ up and running against our data. I am naming mine LINQClasses.
In addition to adding the class files necessary, this will also open the LINQ design surface by default. We can just drag items from our data structure right to the left half of the surface, creating ORM class structures that represent our data. In my example, I only have one table, profile, but we can do this for all of our tables, and stored procedures can be dragged to the right half of the surface, creating methods. I have already dragged my table over in the next screenshot (click to enlarge).
We also want to make sure that our data is unidirectionally serializable (I like big words). By clicking on the design surface (not one of the table boxes), you can get to the properties of the DataContext, and change the Serialization Mode to “Unidirectional.”
Add the service as a reference
Now we need our Silverlight project to become aware of our WCF service running in the web application project. To do this, we just need to add a new service reference to the Silverlight project. Click the “Discover” button to find it automatically. This will also automatically spin up a web server for your service to run in. I named my service reference MyNewServiceReference.
It’s time to write some code
To this point, everything has been handled automatically for us. Now we have to get our hands dirty. Let’s go back to our Service interface (IMyNewService.cs). In there, let’s get rid of that DoWork() method. Instead, our method is going to return a List of profiles from the database, based on our new classes that were created for us. Because this is an interface, we don’t define the actual functionality of the method here, just it’s signature. I named my method GetProfilesByLastName.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace JBWCFServiceWeb
{
// NOTE: If you change the interface name "IMyNewService"
//here, you must also update the reference to
//"IMyNewService" in Web.config.
[ServiceContract]
public interface IMyNewService
{
[OperationContract]
List<profile> GetProfilesByLastName(string lastname);
}
}
Ok, that was exhausting. Let’s have the IDE write some more code for us now. Let’s open the code-behind file for MyNewService.svc (MyNewService.svc.cs). You can see that it inherits from the interface we just defined, so right click on the name of the interface, and have it implement the interface for you.
Now you’ve got the shell for the method. We just need to tell this method what to do. Here’s where the LINQ comes into play. We need to get a reference to our DataContext from earlier, and then I wrote a simple query to retrieve names from the database based on a last name query. Finally, we return our list of data.
public List<profile> GetProfilesByLastName(string lastname)
{
JBWCFServiceWeb.LINQClassesDataContext db = new LINQClassesDataContext();
var data = from p in db.profiles
where p.lastname.StartsWith(lastname)
select p;
return data.ToList();
}
Each time we update our service, we will need to update our service reference in the Silverlight project, so that it sees our new methods. Just right click on the service reference and choose “Update Service Reference.” Also, we have one small change we need to make to our web.config file as well. If you’ve been following the instructions, then you can scroll down to the bottom of your web.config and look for the <endpoint binding=”wsHttpBinding” /> property. Silverlight only currently supports basicHttpBinding, so we need to change it to that.
<services>
<service behaviorConfiguration="JBWCFServiceWeb.MyNewServiceBehavior" name="JBWCFServiceWeb.MyNewService">
<endpoint address="" binding="basicHttpBinding" contract="JBWCFServiceWeb.IMyNewService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
Next, we need to add one more reference to our Silverlight project before we can finally start working with the XAML. We need to add a reference to System.Windows.Controls.Data so that we can use the DataGrid control in our interface.
XAML time
We need to include that reference as a namespace in our Page.xaml document. OK, now we can add some controls to our page. I also added a Button, a TextBox, and a DataGrid, inside a couple of StackPanels, for layout purposes.
<UserControl x:Class="JBWCFService.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:swcd="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Width="400" Height="300">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="10">
<TextBox x:Name="DataEntry" Width="100" Height="25"/>
<Button Width="50" Height="25" Content="Search" Click="Button_Click" />
</StackPanel>
<swcd:DataGrid x:Name="DataGrid" AutoGenerateColumns="True"></swcd:DataGrid>
</StackPanel>
</UserControl>
Calling our service
Now, we need to call that method in our service and populate that grid. The first thing we need to do is instantiate our ServiceClient. Now, since we are calling this service asynchronously, we also need to set up an event handler to know when our data has returned so that we can update the DataGrid. There’s an excellent bit of shorthand for creating this code automatically. My screenshot shows all of the code I will need, but for the line that starts:
sc.GetProfilesByLastName +=
I only actually typed what is above. After that, I pressed the Tab key twice. The first press of Tab actually finishes out my EventHandler statement. The second Tab press creates my EventHandler method, so that I can add the guts. Finally in my Button_Click method, I need to call the GetProfilesByLastName asynchronously, passing in the value from my TextBox, named DataEntry.
private void Button_Click(object sender, RoutedEventArgs e)
{
MyNewServiceReference.MyNewServiceClient sc = new JBWCFService.MyNewServiceReference.MyNewServiceClient();
sc.GetProfilesByLastNameCompleted += new EventHandler<JBWCFService.MyNewServiceReference.GetProfilesByLastNameCompletedEventArgs>(sc_GetProfilesByLastNameCompleted);
sc.GetProfilesByLastNameAsync(DataEntry.Text);
}
The last little touch we need to put on this application is the actual binding of the data to our DataGrid, and we’ll do that in the new EventHandler method that was created for us. There’s just one line of code in the method:
DataGrid.ItemsSource = e.Result;
void sc_GetProfilesByLastNameCompleted(object sender, JBWCFService.MyNewServiceReference.GetProfilesByLastNameCompletedEventArgs e)
{
DataGrid.ItemsSource = e.Result;
}
So, there you have it. We’ve created a WCF service that uses LINQ to talk to a SQL server, and a Silverlight application that consumes that service and renders the result. Not bad for 17 steps, and only a few lines of code.
Leave a Reply