jump to navigation

Using WCF services in WPF applications January 17, 2012

Posted by fofo in C#, Visual Studio 2008, Visual Studio 2010, VS 2010, WCF Service, WPF, XAML.
trackback

In this post I will provide you with hands-on examples on how to retrieve data from a WCF service and bind the data to a WPF data bindable control that resides inside a WPF window. This is not going to be a post that will look into WCF Services in great detail. In the near future I will be writing posts on WCF.In a nutshell WCF provides a unified programming model for building service oriented applications. You write your service once and you can expose it (through endpoints) to multiple protocols without having to rewrite the service.The service is written in a .Net language and consists of operations that are exposed so clients can execute them.When you host the service you make it available to clients by providing one or more endpoints. Bindings are used to determine how a service endpoint will communicate with a client endpoint.

Obviously we can use other ways to talk to data sources. We can use  ADO.Net, datasets, LinqToSQL, Entity Framework,Web services,WCF data services and custom data objects to fetch data from a data source and bind it our WPF controls.

Let’s move on with our hands-on examples.Ι will provide several examples. In the first one I will use a custom data object. In the second one I will use a database.

I assume that you have access to a version of SQL Server and AdventureWorkLT database.

If you do not, you can download and install the free SQL Server Express edition from here. If you need the installation scripts for the sample AdventureWorksLT database, click here . We will use our WCF service to get data from the the Customers table of the AdventureWorksLT database.

1) Launch Visual Studio. I will be using Visual Studio 2010 Ultimate edition. I will be using C# as the development language.

2) Add a WPF application to your solution. Give it a meaningful name. Add a  WCF Service application to your solution.Give it a meaningful name.Visual Studio will create the necessary files.Rename the service from Service1 (IService1) to FootballerService (IFootballerService).

3) Now we are ready to write some code in the IFootballerService.cs file.We need to define the method will get the customers from the database table.


[ServiceContract]
public interface IFootballerService
{

[OperationContract]

List<Footballer> GetFootballers();

// TODO: Add your service operations here
}

4) I will also need to create a DataContract.Since I pass instances of the Footballer object I need to do that.

This is the code.

[DataContract]
public class Footballer
{

[DataMember]
public int FootballerID { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public string Position { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember]
public string PlaysFor { get; set; }

public Footballer( int id,string name,string surname,string position,int age,string playsfor)
{
this.FootballerID = id;
this.FirstName = name;
this.LastName = surname;
this.Position = position;
this.Age = age;
this.PlaysFor = playsfor;
}

}

I am decorating the Footballer class as DataContract.We need to do that so .Net WCF serialiser can take those .Net objects and serialise them to XML so they can passed back to the clients.It knows how to do that with simple types but not with more complex ones. So that is why we must tell it.Do not forget that we still exchange XML SOAP messages over HTTP(or TCP).

5) Now we are ready to implement the Interface.We open the FootballerService.svc.cs file and we write the following code.

public class FootballerService : IFootballerService
{
public List<Footballer> GetFootballers()
{
   var footballers = new List<Footballer>();
   footballers.Add(new Footballer(1, "Steven", "Gerrard", "Attacking Midfielder" ,31 ,"Liverpool"));
   footballers.Add(new Footballer(2, "Lionel", "Messi", "Striker",24,"Barcelona"));
   footballers.Add(new Footballer(3, "Ryan", "Giggs", "Winger", 38, "Man United"));
   return footballers;
}
}

6) Test your service. The host ( the service must be hosted somewhere ) in our example is the ASP.Net development server.

7) Now let’s call the service from the client. The first thing to do is to add a service reference to the WPF application (client project).

Click Add Service Reference and then hit  Discover button (in the new window that will pop up).You will see the service. Give the namespace a meaningful name (CustomersServices).Click Advanced and then in the Data type – Collection type, select the System.Collections.ObjectModel.ObservableCollection  and click OK.Visual Studio will generate all the necessary proxy classes.

8) Let’s add some xaml code on the WPF window.I will use  a ListBox and TextBlock control.


<Grid>
<StackPanel>

<ListBox Name="FootballerBox" Height="300" Margin="28" BorderBrush="Cyan"
DisplayMemberPath="FirstName" SelectionChanged="FootballerBox_SelectionChanged" />
<TextBlock Name="FootballerText" Margin="20,2,2,2"></TextBlock>

</StackPanel>
</Grid>

9) Now we need to add some simple code in the code behind file and for the Window_Loaded events and FootballerBox_SelectionChanged event handling routines.


/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private FootballerServices.FootballerServiceClient footballersService = null;

private void Window_Loaded(object sender, RoutedEventArgs e)
{

footballersService = new FootballerServices.FootballerServiceClient();
try
{
FootballerBox.ItemsSource = footballersService.GetFootballers();
}
catch (Exception ex)
{

MessageBox.Show(ex.Message);
}

}

private void FootballerBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var footballer = (FootballerServices.Footballer)FootballerBox.SelectedItem;

FootballerText.Text = String.Format("His surname is {0}. His age is {1} and the position he plays is {2}.He plays for {3}", footballer.LastName,footballer.Age,footballer.Position,footballer.PlaysFor);

}
}

10) Run your application. You will see the ListBox control populated from the data the WCF service sends to it.When you select a name from the listbox you will see more details for the footballer on the textblock control.

11) Now we will move to the second example.In this example we will get data from the AdventureWorksLT database. Close your solution and create a new WPF application.Give it an appropriate name.

12) Let me explain what I want to do in the example. I will have my main WPF window (MainWindow.xaml). I will place a button on it.Then I will create another WPF window and I will name it GetCustomers (Getcutomers.xaml).In this window I will have a ListBox control and various textblock and textbox controls. In the ListBox control I will only get the CompanyName of the customer.When the user selects the CompanyName in the ListBox control more information will appear in the TextBox controls.This is our client application.Let’s have a look in the markup for the MainWindow.xaml window.


<Grid>
<StackPanel>

<Button Content="Get a list of customers"
Name="listOfCustomersButton"
MaxWidth="200" MinHeight="35" Margin="5,25,5,5"
Click="listOfCustomersButton_Click"/>

</StackPanel>
</Grid>

Add another window in the WPF application.Name it GetCustomers (GetCustomers.xaml). Now let’s have a look at the code behind for the MainWindow.xaml.cs.


private void listOfCustomersButton_Click(object sender, RoutedEventArgs e)
{
        var getCustomers = new GetCustomers();
        getCustomers.Show();
}

13)We need to create a service that will get the data from the underlying database. Create a WCF Service Application and give it an appropriate name. Now you have two projects in your solution.Name the service AdventureWorksService (IAdventureWorksService.cs). Now we need to define the service contract, the public methods that can be accessible from the client and finally the DataContracts.The code follows.


[ServiceContract]
public interface IAdventureWorksService
{
[OperationContract]
List<CustomerSummary> GetCustomers();

[OperationContract]
Customer GetCustomer(int customerID);

}

[DataContract]
public class CustomerSummary
{
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public string CompanyName { get; set; }
//[DataMember]
//public string City { get; set; }
//[DataMember]
//public string Country { get; set; }
}

[DataContract]
public class Customer
{
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string MiddleName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public string CompanyName { get; set; }
[DataMember]
public string SalesPerson { get; set; }
[DataMember]
public string EmailAddress { get; set; }
[DataMember]
public string Phone { get; set; }

}

I am going to have two methods.The first one GetCustomers (which will be implemented later on and used to bind the company name to the ListBox control) will return the CustomerID and CompanyName fields from the database.The second method GetCustomer will return more information about the Customer when we pass it the CustomerID as an input parameter.The fields we are interested in are CustomerID,Title,FirstName,MiddleName,LastName,CompanyName,SalesPerson,EmailAddress,Phone

This is the method that will populate the variousTextbox controls in the GetCustomers window when the user selects the Company Name from the ListBox control.

That is why need to define two classes Customer and CustomerSummary.

14) Now we need to implement the methods in the AdventureWorksService.svc.cs file.The code follows.


public class AdventureWorksService : IAdventureWorksService
{

private CustomerSummary customerSummary = null;
private List<CustomerSummary> customers = null;
private Customer customer = null;

string connectionString = ConfigurationManager.ConnectionStrings["AdventureWorksLTConnectionString"].ConnectionString;

public List<CustomerSummary> GetCustomers()
{
customers = new List<CustomerSummary>();

using (var cnn = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand(
"SELECT TOP 5  CustomerID, CompanyName " +
"FROM SalesLT.Customer ORDER BY CustomerID", cnn))
{
cnn.Open();
using (SqlDataReader CustomersReader =
cmd.ExecuteReader())
{
while (CustomersReader.Read())
{
customerSummary = new CustomerSummary();
customerSummary.CustomerId =
CustomersReader.GetInt32(0);
customerSummary.CompanyName =
CustomersReader.GetString(1);

customers.Add(customerSummary);
}
}
}
}
return customers;
}

public Customer GetCustomer(int customerID)
{
customer = new Customer();

using (var cnn = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand(
"SELECT CustomerID,Title,FirstName,MiddleName,LastName,CompanyName,SalesPerson,EmailAddress,Phone FROM SalesLT.Customer " +
"WHERE CustomerID = @customerId", cnn))
{
cmd.Parameters.Add(new SqlParameter(
"@customerId", customerID));
cnn.Open();
using (SqlDataReader CustomersReader =
cmd.ExecuteReader())
{
while (CustomersReader.Read())
{
customer.CustomerId =
CustomersReader.GetInt32(0);

if (CustomersReader.IsDBNull(1) == true)
{
customer.Title = string.Empty;
}
else
{
customer.Title =
CustomersReader.GetString(1);
}

customer.FirstName =
CustomersReader.GetString(2);

if (CustomersReader.IsDBNull(3) == true)
{
customer.MiddleName = string.Empty;
}
else
{
customer.MiddleName =
CustomersReader.GetString(3);
}

customer.LastName =
CustomersReader.GetString(4);

if (CustomersReader.IsDBNull(5) == true)
{
customer.CompanyName = string.Empty;
}
else
{
customer.CompanyName =
CustomersReader.GetString(5);
}
if (CustomersReader.IsDBNull(6) == true)
{
customer.SalesPerson = string.Empty;
}
else
{
customer.SalesPerson =
CustomersReader.GetString(6);
}
if (CustomersReader.IsDBNull(7) == true)
{
customer.EmailAddress = string.Empty;
}
else
{
customer.EmailAddress =
CustomersReader.GetString(7);
}
if (CustomersReader.IsDBNull(8) == true)
{
customer.Phone = string.Empty;
}
else
{
customer.Phone =
CustomersReader.GetString(8);
}

}
}
}
}
return customer;
}

}

Let me explain what I am doing here.I am getting the connection string

   string connectionString =
ConfigurationManager.ConnectionStrings["AdventureWorksLTConnectionString"].ConnectionString;

In the web.config you need to add those lines of code.


<connectionStrings>

<add name="AdventureWorksLTConnectionString"
connectionString="Data Source=.;Initial Catalog=AdventureWorksLT;Integrated Security=True" />

</connectionStrings>

For the GetCustomers method I create a new connection object and open the connection. I create a new SQLCommand object that holds the query and I execute the query. I loop through the results of the query and get the CustomerID and CompanyName values for each customer.

For the GetCustomer method, I create a new connection object and open the connection. I create a new SQLCommand object that holds the query and I execute the query.In this query I need to pass the parameter as well and I do that.Then I loop through the results.As you see I also take into account if the field has the NULL value.

Finally I return a customer object that holds the values of CustomerID,Title,FirstName,MiddleName,LastName,CompanyName,SalesPerson,EmailAddress,Phone for the particular CustomerID value I pass as the input parameter.

15) Now we need to add the markup for the GetCustomers.xaml page.The markup follows. You need to paste it in your own window and it will make sense.In order for you to understand what is going on it will be handy if you know a few things of how data binding works in WPF.


<Window.Resources>
<DataTemplate x:Key="CustomerTemplate">
<StackPanel Margin="0,0,0,5"
Orientation="Horizontal">
<TextBlock Margin="10,0,0,0"
VerticalAlignment="Center"
Text="{Binding Path=CompanyName}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="250" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Name="customersListBox"
Grid.Row="0" Margin="10"
BorderBrush="Black"
ItemTemplate="{StaticResource CustomerTemplate}"
SelectionChanged="customersListBox_SelectionChanged"/>
<Grid Name="customerGrid" Grid.Row="1" Margin="5,0,0,0" Width="450" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Title"
Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10,0,0,0" />
<TextBox Text="{Binding Path=Title}"
Grid.Row="0" Grid.Column="1"
Margin="3" Height="25" />
<TextBlock Text="First Name"  Grid.Row="1" Grid.Column="0"  VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" />
<TextBox Text="{Binding Path=FirstName}" Grid.Row="1" Grid.Column="1" Margin="3" Height="25" />
<TextBlock Text="Middle Name" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="10,0,0,0" />
<TextBox Text="{Binding Path=MiddleName}"
Grid.Row="2" Grid.Column="1" Margin="3" Height="25" />
<TextBlock Text="Last Name" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center"  HorizontalAlignment="Left"  Margin="10,0,0,0" />
<TextBox Text="{Binding Path=LastName}" Grid.Row="3" Grid.Column="1"Margin="3" Height="25" />
<TextBlock Text="Company Name" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center"   HorizontalAlignment="Left"   Margin="10,0,0,0" />
<TextBox Text="{Binding Path=CompanyName}" Grid.Row="4" Grid.Column="1" Margin="3" Height="25" />
<TextBlock Text="Sales Person" Grid.Row="5" Grid.Column="0"  VerticalAlignment="Center" HorizontalAlignment="Left"  Margin="10,0,0,0" />
<TextBox Text="{Binding Path=SalesPerson}" Grid.Row="5" Grid.Column="1" Margin="3" Height="25" />
<TextBlock Text="Email" Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" />
<TextBox Text="{Binding Path=EmailAddress}" Grid.Row="6" Grid.Column="1" Margin="3" Height="25" />
<TextBlock Text="Phone" Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" />
<TextBox Text="{Binding Path=Phone}" Grid.Row="7" Grid.Column="1" Margin="3" Height="25" />
HorizontalAlignment="Left"  Margin="10,0,0,0" />
</Grid>
</Grid>
</Window>

16) we need to add a service referenceto the WPF application (client project).

Click Add Service Reference and then hit  Discover button (in the new window that will pop up).You will see the service. Give the namespace a meaningful name (WCFAdventureWorksServices).Click Advanced and then in the Data type – Collection type, select the System.Collections.ObjectModel.ObservableCollection  and click OK.Visual Studio will generate all the necessary proxy classes.

17) The code behind for the GetCustomers.xaml.cs file follows.The code is extremely easy to follow. I use the Window_Loaded event to bind data to the ListBox control.I do that by setting the ItemSource property of the ListBox (CustomersListBox) control to the GetCustomers method of the service.When the user selects a value from the ListBox the Selection_Changed event is fired and I set the DataContext property of the Grid to the values of the GetCustomer method.


private WCFAdventureWorksServices.AdventureWorksServiceClient
advService = null;

private void Window_Loaded(object sender, RoutedEventArgs e)
{
advService = new
WCFAdventureWorksServices.AdventureWorksServiceClient();
try
{
customersListBox.ItemsSource =
advService.GetCustomers();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void customersListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int customerID =
((WCFAdventureWorksServices.CustomerSummary)
((ListBox)sender).SelectedItem).CustomerId;
try
{
customerGrid.DataContext = advService.GetCustomer(customerID);

}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

17) Run your application and make sure that everything works as expected. Click on the Company Names values in the ListBox control and see the details for each customer appearing in the TextBox controls.

Leave a comment if you need the source code.

Hope it helps!!!!

Comments»

1. Dot Net Rules : Using WCF services in WPF applications - January 17, 2012

[…] a nutshell WCF provides a unified programming model for building service oriented applications. (read more) Share Posted: Τρίτη, 17 Ιανουαρίου 2012 9:48 μμ από το μέλος […]

2. sam - July 20, 2012

Wonderful article

3. Davis - July 26, 2012

Thanks so much

4. zero - October 30, 2012

THX…

5. Gustavo - May 10, 2013

Hello, good article. If possible I need the source code.

6. Hoa - November 21, 2013

Wonderful article. If possible I need the source code.thanks.

7. Preguntón Cojonero (@preguntoncabron) - October 22, 2014
8. Suja - April 5, 2015

Very nice


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: