Thursday, November 6, 2008

How to call WCF methods from Silverlight controls ?


 


This tutorial and the attached sample project demonstrates how to access server side data from Silverlight controls using WCF.


Silverlight controls get executed on the client browser. It does not have direct access to the data on the serverside. So, if your Silverlight controls need to retrieve data from database or other data sources on the server, we have to use various approaches like WCF calls or depend on the InitParameters property of the Silverlight controls.

The recommended approach to get server side data to Silverlight controls is using WCF method calls. The most important benefit is the type safety.

The following sample demonstrates how to use WCF to retrieve data from Server side to Silverlight controls on the client side.

In this sample, we will create a Silverlight project and another web project to host the Silverlight control. Also, we will add a WCF Service to the web project.

Silverlight with WCF sample

Create a new Silverlight project with a web project to host the Silverlight control.

Open Visual Studio and select the menu "File" > "New" > "Project"
Select the Project Type as "Silverlight" under your favorite language and choose the template "Silverlight Application". I have selected Visual C# as the tutorials here.

I have named my project as "MySilverlightApp" and have selected the option "Create directory for solution" so that all my project files are organized within a folder structure.



In the next screen, choose the option "Add a new web to the solution for hosting the control".



Right click on the web project in the Solution Explorer and select "Add New Item".

Select the category "Silverlight" from the left panel in the dialog box.

From the right panel, select the template "Silverlight-enabled WCF Service"

Choose the default name "Service1.svc" and press the "Add" button.

(The current beta version of Visual Studio may show you an error object reference not set to an instance .... Ignore this error and proceed.)

You can see the below code:


[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
[OperationContract]
public void DoWork()
{
return;
}
}



Explaining the concepts of WCF is beyond the scope of this tutorial. However, I just want to point out 2 things here:

[ServiceContract(Namespace = "")]

- This attribute above the class name indicates that this class is a WCF service.

[OperationContract]

- This attribute above the method name indicates that this method can be called from a WCF client.

Let us add a new method to our WCF service class, decorated with the [OperationContract] attribute. Add a method as shown below:


[OperationContract]
public string GetName()
{
return "John";
}



As you can see, it is a simple method which returns a hard coded name.

Open your solution explorer. Right click on the file "Service1.svc" and select "Set as Startup Page".

Now run the application by pressing Ctrl + F5 (or, using the menu "Debug" > "Start Without Debugging")

The browser will be opened and Service1 meta data will be displayed. Ignore the content in the page, but copy the URL from the browser. The URL will look something like this:

http://localhost:1873/Service1.svc

The port number may be different in your case, but that is OK.

Return to your Solution Explorer in Visual Studio. Right click on your Silverlight project (not web project) and select "Add Service Reference".

In the field for Address, specify the URL you copied from the browser and press "GO".

In the bottom left, change the namespace to "MySampleService".

You should see a screen like this:



Press "OK" to add the service reference.

Now you can call our WCF service from the Silverlight client.

To test this, follow these steps:

1. Open the Page1.xaml file and add a textblock to display the string returned from the WCF method call.

2. Add an event handler for the "Loaded" event of the UserControl.

Complete code from Page1.xaml is given below:


<UserControl x:Class="Silverlight_With_WCF.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300"
Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="textblock1" Width="200" Height="30"></TextBlock>
</Grid>
</UserControl>



Now go to the code behind file (Page1.xaml.cs) and add the WCF service call as shown below:


private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
MySampleService.Service1Client client = new MySampleService.Service1Client();
client.GetNameCompleted += new EventHandler(client_GetNameCompleted);
client.GetNameAsync();
}
void client_GetNameCompleted(object sender, MySampleService.GetNameCompletedEventArgs e)
{
textblock1.Text = (string)e.Result;
}



Open the web project in Solution Explorer and set the Silverlight test page as the startup page. Now run the project. You can see that the WCF service is called from Silverlight client and the result is displayed in the browser. (In our sample, the result from the WCF call is the name "John" and this name will be displayed in the screen).

You can
download a sample project for this tutorial.


 

Creating a Silverlight 2.0 Application that Consumes a WCF Service


(Page 1 of 4 )

This is my second article in a series focusing on Silverlight 2.0 (beta 2) development using Visual Studio 2008. This article is for beginners who are quite new to Silverlight development and need a practical introduction to developing Silverlight applications which consume WCF services using Visual Studio 2008.

If you are new to Silverlight 2.0 development, please refer my first article in this series titled "Beginning Silverlight 2.0 Development Using Visual Studio 2008."

If you want to learn about the WCF Service and the WCF Service Library, consider reading my WCF articles listed at http://www.aspfree.com/cp/bio/Jagadish-Chatarji.

In this article, we will create a new WCF Service and consume it using the Silverlight 2.0 application. Technically, we will have a Silverlight 2.0 Datagrid control consuming rows from a regular WCF Service.

My development machine is equipped with following environment:

To make this article simple, I created a new database named "Sample" with the following table ("emp") on my machine (Fig 01):


The entire source code for this article is available in the form of a free downloadable zip file. The solution was developed using Microsoft Visual Studio 2008 Team Edition (with SP1) with Microsoft SQL Server 2008 Developer Edition on Microsoft Windows Server 2003 Standard Edition (with SP3) with Silverlight 2.0 Beta 2. I didn't really test it in any other environment. I request that you post in the discussion area if you have any problems in execution.

Developing WCF Service using Visual Studio 2008: Creating the project

Let us start our development with WCF Service.

Create a blank solution (DemoSln) as follows:


 

Add a new WCF Service Application as follows:


The following are the steps to configure the WCF Service to be consumed by the Silverlight 2.0 application. Please understand that the entire following configuration is only for a development environment and the configuration for a production environment might be different.

Change "Service1" to "EmpService" everywhere as follows:


 

<%@ ServiceHost Language="VB" Debug="true" Service="DemoEmpService.EmpService" CodeBehind="EmpService.svc.vb" %>


 

Modify "Web.Config" as follows:


 


 

 <connectionStrings>

<add name="cnSample" connectionString="Data Source=.sql2k5;initial catalog=sample;user id=sa;password=eXpress2005"/>

</connectionStrings>

Configure a virtual path (using Project properties) and add ClientAccessPolicy.xml as follows:



Once you have created and configured your WCF Service as explained in previous sections, you need to develop some code to retrieve rows from the database.

Open "IEmpService.vb" and modify the code so that it looks like the following:


 

<ServiceContract()> _

Public Interface IEmpService


 

<OperationContract()> _

Function GetEmployee(ByVal empno As Integer) As Employee


 

<OperationContract()> _

Function GetEmployeeList() As List(Of Employee)


 

End Interface


 

' Use a data contract as illustrated in the sample below to add composite types to service operations.

<DataContract()> _

Public Class Employee


 

Private _Empno As Integer

Private _Ename As String

Private _Sal As Double

Private _Deptno As Integer


 

<DataMember()> _

Public Property Empno() As Integer

Get

Return _Empno

End Get

Set(ByVal value As Integer)

_Empno = value

End Set

End Property


 

<DataMember()> _

Public Property Ename() As String

Get

Return _Ename

End Get

Set(ByVal value As String)

_Ename = value

End Set

End Property


 

<DataMember()> _

Public Property Sal() As Double

Get

Return _Sal

End Get

Set(ByVal value As Double)

_Sal = value

End Set

End Property


 

<DataMember()> _

Public Property Deptno() As Integer

Get

Return _Deptno

End Get

Set(ByVal value As Integer)

_Deptno = value

End Set

End Property


 

End Class


 

Open "EmpService.svc" and modify the code as follows:


 

Imports System.Data.SqlClient


 

Public Class EmpService

Implements IEmpService


 

Public Sub New()

End Sub


 

Public Function GetEmployee(ByVal empno As Integer) As Employee Implements IEmpService.GetEmployee

Dim objEmp As Employee = Nothing

Using cmd As New SqlCommand("select empno, ename, sal, deptno from dbo.emp where empno = " & empno, New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("cnSample").ConnectionString))


 


 

cmd.Connection.Open()

Dim dr As SqlDataReader = cmd.ExecuteReader

If dr.HasRows Then

dr.Read()

objEmp = New Employee With {.Empno = dr.GetValue(dr.GetOrdinal("Empno")), _

.Ename = dr.GetValue(dr.GetOrdinal("Ename")), _

.Sal = dr.GetValue(dr.GetOrdinal("Sal")), _

.Deptno = dr.GetValue(dr.GetOrdinal("Deptno")) _

}

End If

cmd.Connection.Close()

End Using

Return objEmp


 

End Function


 

Public Function GetEmployeeList() As System.Collections.Generic.List(Of Employee) Implements IEmpService.GetEmployeeList

Dim clnEmp As New List(Of Employee)

Using cmd As New SqlCommand("select empno, ename, sal, deptno from dbo.emp ", New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("cnSample").ConnectionString))


 


 

cmd.Connection.Open()

Dim dr As SqlDataReader = cmd.ExecuteReader

If dr.HasRows Then

While dr.Read

clnEmp.Add(New Employee With {.Empno = dr.GetValue(dr.GetOrdinal("Empno")), _

.Ename = dr.GetValue(dr.GetOrdinal("Ename")), _

.Sal = dr.GetValue(dr.GetOrdinal("Sal")), _

.Deptno = dr.GetValue(dr.GetOrdinal("Deptno")) _

} _

)

End While

End If

cmd.Connection.Close()

End Using

Return clnEmp


 

End Function


 

End Class


 

Build your solution and open "EmpService.svc" in a browser. It should respond with the following (Fig 06).


Developing WCF Service using Visual Studio 2008: Testing WCF Service

The easiest and fastest way to test a WCF Service is by using the "WCF Test Client" which comes with Visual Studio 2008. The other way is to develop our own WCF consumer (say WinForm consumer, Unit Test consumer) and write code to access the WCF Service. We will deal with the first method here (for simplicity). The second method (WinForm consumer) is available in the source download.

WCF Service test using "WCF Test Client":


Now we need to develop a Silverlight 2 application which consumes our regular WCF Service.

The following are the necessary steps to get started:


If you observe the "Solution explorer" now, you will find two projects. One is the Silverlight application itself and the other is simply a web application which is used to render and test the Silverlight application developed.

Now that we've created a new Silverlight application, we need to add a reference to the WCF Service we developed earlier. 

Using "Solution Explorer," right click on the "DemoSL" project and "Add Service Reference" to "DemoEmpService" as shown below (Fig 10). Rebuild the solution.


Modify the "ServiceReferences.ClientConfig" in "DemoSL" as follows (Fig 11). Rebuild the solution.



 

Developing a Silverlight 2 application to consume WCF: Writing code

Drag and drop a button, label and a Datagrid from the toolbox onto the Silverlight design surface. Modify your code so that it looks like the following:


 

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="DemoSL.Page"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Width="400" Height="300">

 <Grid x:Name="LayoutRoot" Background="White">

 <Grid.RowDefinitions>

 <RowDefinition Height="0.15*"/>

 <RowDefinition Height="0.25*"/>

 <RowDefinition Height="0.60*"/>

 </Grid.RowDefinitions>

 <Button HorizontalAlignment="Left" Margin="5,5,0,0" VerticalAlignment="Stretch" Width="76" Content="Show" x:Name="btnShow" Height="30" />

 <TextBlock Margin="5,5,0,0" VerticalAlignment="Stretch" Text="" TextWrapping="Wrap" x:Name="lblMsg" Height="22" Grid.Row="1" />

 <my:DataGrid x:Name="dgEmployees" AutoGenerateColumns="True" Grid.Row="2"></my:DataGrid>

 </Grid>

</UserControl>


 

Once the datagrid control is added to the Silverlight application, you should have a "System.Windows.Controls.Data" assembly added to your reference list. You should also observe the namespace "my" added to the "UserControl" tag.

Go to the code-behind of the "Page.xaml" and modify the code to look like the following:


 

Partial Public Class Page

Inherits UserControl


 

Public Sub New()

InitializeComponent()

End Sub


 

Private Sub EmployeeListFetched(ByVal sender As Object, ByVal e As EmpService.GetEmployeeListCompletedEventArgs)

Me.dgEmployees.ItemsSource = e.Result

Me.lblMsg.Text = "Fetched!"

End Sub


 

Private Sub btnShow_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnShow.Click

Me.lblMsg.Text = "Fetching..."

Dim objService As New EmpService.EmpServiceClient

AddHandler objService.GetEmployeeListCompleted, AddressOf EmployeeListFetched

objService.GetEmployeeListAsync()

End Sub


 

End Class


 

Once you execute your Silverlight application, you should see the output as follows:


 

Fig 12



 

In my upcoming articles, we will see more and more examples of Silverlight 2.0 development. I hope you enjoyed the article and any suggestions, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com