HomeSilverlight Silverlight 4.0 Data Retrieval: Getting Da...
Silverlight 4.0 Data Retrieval: Getting Data from WCF RIA Services
This article focuses on consuming WCF RIA Services using Silverlight 4.0 in a raw manner (that is, without using DomainDataSource and DataForm controls of Silverlight 4.0).
To make this article simple, I managed to create a simple Silverlight 4.0 application which consumes a WCF RIA Service created using the WCF RIA Service Library. If you are not familiar with developing applications using the WCF RIA Service Library and Silverlight 4.0, check out a beginner’s article available at http://jagchat.spaces.live.com/blog/cns!41050F68F010A662!4439.entry
The solution was developed using Microsoft Visual Studio 2010 Ultimate Edition with Microsoft Silverlight 4.0 on Windows 7 Ultimate edition. I didn’t really test it in any other environment. I request that you post in the discussion area if you have any problems with executing the application.
Developing the Silverlight application
Modify your XAML application, which looks like the following code. The next section explains the code.
The above creates the main layout with three rows. The first row is for the fields, the second row is for the buttons and the third is for the DataGrid (which occupies the entire remaining space).
The main layout is done, and now we need to lay out the form fields. To arrange the fields in a tabular fashion, I created another layout (which will sit in the first row of the previous grid) as follows.
<Grid x:Name="lytEmpForm" Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.20*"/>
<ColumnDefinition Width="0.50*"/>
<ColumnDefinition Width="0.30*"/>
</Grid.ColumnDefinitions>
</Grid>
The above creates a table of four rows and three columns within the first row of the “LayoutRoot” Grid Layout (main layout). The third column is only meant for the “Search” button (to separate it from the field pairs). The following code places the controls into the respective cells of the “lytEmpForm” Grid Layout (it is worth paying attention to the Grid.Column and Grid.Row attributes of each of the elements below):
Once the top row of the “LayoutRoot” Grid Layout is filled with fields, we need to fill the second row with operational buttons. I took advantage of “StackPanel” to get all buttons adjacent to each other.
Finally, I need DataGrid to fill the third row (and entire remaining area of the app). It is defined as follows:
Now that we've designed the form, we need to concentrate on pulling data from the WCF RIA Service. Let us start with populating the DataGrid.
To communicate with the WCF RIA Service, we need work within a domain context (indirectly, an instance of DomainService class). In our case, “EmpMgrDomainSvc” is the “DomainContext” class, and we need to create an instance of this class.
The most important point to understand here is that we are about to create an instance of the “EmpMgrDomainSvc” class available in the “BusinessLibGenerated_CodeBusinessLib.Web.g.vb” file. This file gets automatically generated (with asynchronous wrap-ups to existing service operations) every time we compile “BusinessLib.WebEmpMgrDomainSvc.vb”. This happens because the “WCF RIA Services Link” option is set up in the “BusinessLib” project properties as follows:
The following populates the DataGrid when the Silverlight application gets instantiated:
Partial Public Class MainPage
Inherits UserControl
Private oCtxt As New BusinessLib.Web.EmpMgrDomainSvc
Public Sub New()
InitializeComponent()
Me.dgEmp.ItemsSource = oCtxt.emps
oCtxt.Load(oCtxt.GetEmpsQuery())
End Sub
End Class
From the above, you can easily understand that I created a “Context” object (instance of Domain Service), assigned the EntitySet “emps” as an “ItemsSource” to DataGrid, and finally loaded the EntitySet using the following statement:
oCtxt.Load(oCtxt.GetEmpsQuery())
You can also do the same using the following code:
Partial Public Class MainPage
Inherits UserControl
Private oCtxt As New BusinessLib.Web.EmpMgrDomainSvc
Public Sub New()
InitializeComponent()
Dim oLoadOp = oCtxt.Load(oCtxt.GetEmpsQuery())
Me.dgEmp.ItemsSource = oLoadOp.Entities
End Sub
End Class
The Silverlight DataGrid bound to the EntitySet of the WCF RIA Service would look like the following (for now, the columns of DataGrid are auto-generated):
In the previous section, we managed to pull information from the WCF RIA Service in the form of an EntitySet. Once the EntitySet is available to the client (in this case the Silverlight application), we can use LINQ to further manipulate it.
For instance, I can use the following code to search for a particular object in the EntitySet on the client side:
Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSearch.Click
Dim oEmp = oCtxt.emps.SingleOrDefault(Function(p) p.empno = Me.txtEmpno.Text)
If oEmp Is Nothing Then
MessageBox.Show("Employee not found")
Else
Me.lytEmpForm.DataContext = oEmp
End If
End Sub
The above would try to find an instance in the “emps” EntitySet using LINQ to Entities and if found, the data would be displayed in the textboxes (with the help of the “DataContext” property). This is not very interesting if you are already familiar with LINQ and a bit of Silverlight Binding.
Let us imagine that I have thousands of employees in a database. When I try to load EntitySet “emps” using “ctxt.Load(ctxt.GetEmpsQuery())”, it will query all employees in the table, fill the entity set with all of the rows at the server, serialize all objects and finally send the whole set to the client (Silverlight app) over the wire. This would lead to tremendous performance issues when dealing with huge amounts of data.
Every developer knows that they should only retrieve what they need to show on the screen (but not the entire table/database). That means we need to execute customized queries at the WCF RIA Service level. “Query Methods” in WCF RIA Services give us the ability to write our own customized queries.
Let us try to retrieve only one object (say, one employee) from the database using a new query method. Modify “BusinessLib.WebEmpMgrDomainSvc.vb” to add the following:
<Query(IsComposable:=False)>
Public Function GetEmpsByEmpno(ByVal empno As Integer) As emp
It is always recommended that you write your custom query methods in a separate file (using partial classes) so that you won’t lose your customization when you synchronize an EF model with the database in the future.
Once you compile your solution, the above signature will turn into the following in “BusinessLibGenerated_CodeEmpMgrDomainSvc.g.vb,” and the same is accessible at the Silverlight client:
Public Function GetEmpsByEmpnoQuery(ByVal empno As Integer) As EntityQuery(Of emp)
At the Silverlight client, you can access the above using the following:
Private oCurrentEmp As BusinessLib.Web.emp
Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSearch.Click
Private Sub EmployeeLoadedCallback(ByVal lo As LoadOperation(Of BusinessLib.Web.emp))
If lo.Entities.Count = 0 Then
MessageBox.Show("Employee not found")
Else
oCurrentEmp = lo.Entities(0)
Me.lytEmpForm.DataContext = oCurrentEmp
End If
End Sub
Once you do the search, you'll receive the result shown below:
My next article will concentrate on CRUD operations with WCF RIA Services using Silverlight. I hope you enjoyed the article; any suggestions, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com