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:
- Windows Server 2003 with SP2
- IIS
- SQL Server 2008
- Visual Studio 2008 (comes with .NET 3.5) with SP1
- Microsoft Silverlight Tools Beta 2 for Visual Studio 2008 (includes Silverlight, Silverlight SDK and Tools for VS 2008)
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:
- Go to File || New || Project.
- At the top of the "New Project" dialog, make sure that you have selected ".NET Framework 3.5" as your target .NET version.
- In the "Project Type" (left pane of "New Project" dialog), open "Visual Studio Solutions" in "Other Project Types."
- In the "Templates" (right pane of "New Project" dialog), select "Blank Solution."
- Provide "DemoSln" as the "Name," your own location, and click "OK."
Add a new WCF Service Application as follows:
- Go to File || Add || New Project (to the existing solution).
- In "Add New Project," make sure ".NET Framework 3.5" is selected at the top.
- Open "Visual Basic" || "Web" in the "Project Types" list.
- Select "WCF Service Application" as the template.
- Provide "DemoEmpService" as the name (Fig 02) and click on "OK."
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:
- Using Solution Explorer, right click on "IService1.vb" and rename it to "IEmpService.vb."
- The above should replace the existing interface "IService1" to "IEmpService" everywhere in the code. If it does not do it automatically, you have to do it manually yourself.
- Using Solution Explorer, right click on "Service1.svc" and rename it to "EmpService.svc."
- Go to the code-behind of the same file and change the class name "Service1" to "EmpService."
- Right click on "EmpService.svc" again and select "Open with."
- Now you have to modify the service file itself. In the "Open with" list, select "Source Code (Text) Editor" and click "OK."
- Modify the existing line so that it matches the following:
<%@ ServiceHost Language="VB" Debug="true" Service="DemoEmpService.EmpService" CodeBehind="EmpService.svc.vb" %>
- Save all.
Modify "Web.Config" as follows:
- Open "Web.Config" and modify Service model configuration as follows (Fig 03)
- Add the connection string as follows (modify this according to your environment):
<connectionStrings>
<add name="cnSample" connectionString="Data Source=.sql2k5;initial catalog=sample;user id=sa;password=eXpress2005"/>
</connectionStrings>
- Save all
Configure a virtual path (using Project properties) and add ClientAccessPolicy.xml as follows:
- Using "Solution Explorer," right click on "DemoEmpService" project and select "Properties."
- Go to the "Web" tab and in the "Server" section, select "Use Local IIS Web Server."
- Provide "http://localhost/DemoEmpService" as the project URL, check on "Override application root" and click on "Create Virtual Directory" (Fig 04).
- Save all.
- Make sure that "DemoEmpService" is listed in IIS and configured with "ASP.NET 2.0" runtime.
- Make sure that both "Anonymous Authentication" and "Integrated Authentication" are enabled for "DemoEmpService" in IIS.
- In your web virtual root (usually c:inetpubwwwroot), create a new file , name it "ClientAccessPolicy.xml" and copy the following code (Fig 05).
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":
- Open Start || Programs || Visual Studio 2008 || Visual Studio Tools || Visual Studio 2008 Command Prompt.
- At the prompt, type "wcftestclient" and press enter.
- You should see "WCF Test Client" opened for you.
- Go to File || Add service, provide "http://localhost/DemoEmpService/EmpService.svc" as the endpoint address and click "OK."
- It should connect to your WCF service and show you the list of web methods.
- Double click on those methods and start testing as follows (Fig 07):
Now we need to develop a Silverlight 2 application which consumes our regular WCF Service.
The following are the necessary steps to get started:
- Open Visual Studio 2008.
- Go to File || Add || New Project (to the existing solution).
- Select "Silverlight" as the "Project Type," "Silverlight Application" as the "Template," "DemoSL" as the "Name" and finally click "OK."
- You will be provided with an "Add Silverlight Application" dialog.
- Select "Add a new Web to the solution" (first radio button).
- Select "Web Application Project" as the "Project Type," "DemoSLWeb" as the "Name" and finally click on "OK" (as shown in Fig 09).
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