Silverlight has been around for quite some time now and I hope most of you who have been working on Silverlight 3.0, might have started migrating to Silverlight 4.0. As you are aware, Silverlight is now used for developing LOB applications where the requirement is to develop loosely coupled browser based applications using Silverlight. One of the approaches here is to remove the dependency between Model and View (UI) so that they can be developed and tested independent from each other. This article shows how to create a Silverlight application that consumes a WCF service keeping minimum dependencies between the Model and View
In this article, I have used WCF service which is responsible for Database communication. You can use ADO.NET entity framework and ADO.NET Data service instead of writing data access code in WCF, but we will leave that to a different article.
Note: In this article I have used VS2010 RC, WCF 4.0 and Silverlight 4.0.
Step 1: Open VS2010 and create a blank solution, name it as ‘SILV4_MVVM’.
Step 2: To this solution, add a WCF application project, name it as ‘WCF_DataService’. Rename ‘IService1’ to ‘IService’ and ‘Service1.svc’ to ‘Service.svc’.
Step 3: To this WCF Service project, add a new class and name it as ‘DbManager’. This class will act as a Database communication class. Write the implementation of the class as shown below [Please use try catch blocks where required]
C#
using System.Data;
using System.Data.SqlClient;
namespace WCF_DataService
{
public static class DbManager
{
static SqlConnection Conn;
public static void OpenConnection()
{
Conn = new SqlConnection("Data Source=.\\dbServer;Initial Catalog=Company;Integrated Security=SSPI");
Conn.Open();
}
public static DataTable GetAllRecords(string query)
{
SqlCommand Cmd = new SqlCommand();
Cmd.Connection = Conn;
Cmd.CommandText = query;
SqlDataReader Reader = Cmd.ExecuteReader();
DataTable dtVal = new DataTable();
dtVal.Load(Reader);
return dtVal;
}
public static void PerformDML(string query)
{
SqlCommand Cmd = new SqlCommand();
Cmd.Connection = Conn;
Cmd.CommandText = query;
Cmd.ExecuteNonQuery();
}
public static void CloseConnection()
{
if (Conn.State == ConnectionState.Open)
{
Conn.Close();
}
}
}
}
VB.NET
Imports System.Data
Imports System.Data.SqlClient
Namespace WCF_DataService
Public NotInheritable Class DbManager
Private Shared Conn As SqlConnection
Private Sub New()
End Sub
Public Shared Sub OpenConnection()
Conn = New SqlConnection("Data Source=.\dbServer;Initial Catalog=Company;Integrated Security=SSPI")
Conn.Open()
End Sub
Public Shared Function GetAllRecords(ByVal query As String) As DataTable
Dim Cmd As New SqlCommand()
Cmd.Connection = Conn
Cmd.CommandText = query
Dim Reader As SqlDataReader = Cmd.ExecuteReader()
Dim dtVal As New DataTable()
dtVal.Load(Reader)
Return dtVal
End Function
Public Shared Sub PerformDML(ByVal query As String)
Dim Cmd As New SqlCommand()
Cmd.Connection = Conn
Cmd.CommandText = query
Cmd.ExecuteNonQuery()
End Sub
Public Shared Sub CloseConnection()
If Conn.State = ConnectionState.Open Then
Conn.Close()
End If
End Sub
End Class
End Namespace
Step 4: Write the following code in ‘IService.cs’
C#
namespace WCF_DataService
{
[ServiceContract]
public interface IService
{
[OperationContract]
Employee[] GetAllEmployees();
}
[DataContract]
public class Employee
{
[DataMember]
public int EmpNo { get; set; }
[DataMember]
public string EmpName { get; set; }
[DataMember]
public int Salary { get; set; }
[DataMember]
public int DeptNo { get; set; }
}
}
VB.NET
Namespace WCF_DataService
<ServiceContract> _
Public Interface IService
<OperationContract> _
Function GetAllEmployees() As Employee()
End Interface
<DataContract> _
Public Class Employee
Private privateEmpNo As Integer
<DataMember> _
Public Property EmpNo() As Integer
Get
Return privateEmpNo
End Get
Set(ByVal value As Integer)
privateEmpNo = value
End Set
End Property
Private privateEmpName As String
<DataMember> _
Public Property EmpName() As String
Get
Return privateEmpName
End Get
Set(ByVal value As String)
privateEmpName = value
End Set
End Property
Private privateSalary As Integer
<DataMember> _
Public Property Salary() As Integer
Get
Return privateSalary
End Get
Set(ByVal value As Integer)
privateSalary = value
End Set
End Property
Private privateDeptNo As Integer
<DataMember> _
Public Property DeptNo() As Integer
Get
Return privateDeptNo
End Get
Set(ByVal value As Integer)
privateDeptNo = value
End Set
End Property
End Class
End Namespace
The above code shows the ServiceContract as well as DataContract used in WCF service.
Step 5: Open Service.cs and write the following implementation:
C#
namespace WCF_DataService
{
public class Service : IService
{
public Employee[] GetAllEmployees()
{
DbManager.OpenConnection();
string strEmp = "Select * from Employee";
DataTable dtVal = DbManager.GetAllRecords(strEmp);
Employee[] arrEmp = new Employee[dtVal.Rows.Count];
int i = 0;
foreach (DataRow Dr in dtVal.Rows)
{
arrEmp[i] = new Employee()
{
EmpNo = Convert.ToInt32(Dr["EmpNo"]),
EmpName = Dr["EmpName"].ToString(),
Salary = Convert.ToInt32(Dr["Salary"]),
DeptNo = Convert.ToInt32(Dr["DeptNo"])
};
i++;
}
DbManager.CloseConnection();
return arrEmp;
}
}
}
VB.NET
Namespace WCF_DataService
Public Class Service
Implements IService
Public Function GetAllEmployees() As Employee()
DbManager.OpenConnection()
Dim strEmp As String = "Select * from Employee"
Dim dtVal As DataTable = DbManager.GetAllRecords(strEmp)
Dim arrEmp(dtVal.Rows.Count - 1) As Employee
Dim i As Integer = 0
For Each Dr As DataRow In dtVal.Rows
arrEmp(i) = New Employee() With {.EmpNo = Convert.ToInt32(Dr("EmpNo")), .EmpName = Dr("EmpName").ToString(), .Salary = Convert.ToInt32(Dr("Salary")), .DeptNo = Convert.ToInt32(Dr("DeptNo"))}
i += 1
Next Dr
DbManager.CloseConnection()
Return arrEmp
End Function
End Class
End Namespace
Step 6: Build the service and publish it in IIS. To test this service, make sure that you are able to successfully browse Service.svc and can see the WSDL.
Note: We are not making any changes in Web.Config file because WCF 4.0 has default configuration. This uses ‘basicHttpBinding’ and since this WCF service is going to be used in Silverlight, BasicHttpBinding is any way required.
Creating a Silverlight client
Step 7: To the solution, add a new ‘Silverlight Class Library’ project and name it as ‘Silv4.Company.View.ModelVew’. To this project, add two new folders - first named as ‘Model’ which contains all model classes. The second folder named ‘ViewModel’ which contains all ViewModel classes.
Step 8: To this project, add service reference to the WCF service. As soon as you do that, you will see that Service Reference and ‘ServiceReferences.config’ gets added to the project. The project structure will be as shown below:
This service reference will add ‘Employee’ class.
Step 9: In the model folder, add a new class and name it as ‘EmployeeOperationEventArgs’. This class contains arguments definition, which will contain data from Model to View. The code is as shown below:
C#
using Silv4.Company.View.ModelVew.MyRef;
namespace Silv4.Company.View.ModelVew.Model
{
public class EmployeeOperationsEventArgs : EventArgs
{
//Declare a Enumerable, representing return values, when call is made to the service
public IEnumerable<Employee> AllEmployees { get; set; }
public EmployeeOperationsEventArgs(IEnumerable<Employee> allEmployees)
{
AllEmployees = allEmployees;
}
}
}
VB.NET
Imports Silv4.Company.View.ModelVew.MyRef
Namespace Silv4.Company.View.ModelVew.Model
Public Class EmployeeOperationsEventArgs
Inherits EventArgs
'Declare a Enumerable, representing return values, when call is made to the service
Private privateAllEmployees As IEnumerable(Of Employee)
Public Property AllEmployees() As IEnumerable(Of Employee)
Get
Return privateAllEmployees
End Get
Set(ByVal value As IEnumerable(Of Employee))
privateAllEmployees = value
End Set
End Property
Public Sub New(ByVal allEmployees As IEnumerable(Of Employee))
AllEmployees = allEmployees
End Sub
End Class
End Namespace
Step 10: In the Model folder, add a new interface and name it as ‘IEmployee’. Write the following code:
C#
namespace Silv4.Company.View.ModelVew.Model
{
public interface IEmployee
{
void GetAllEmployees();
//The Following event is used for notification
//for the Operation completed by the ViewModel.
//This is REquired because the SIlverlight applications
//makes async call to service.
event EventHandler<EmployeeOperationsEventArgs> GetAllEmployeesCompleted;
}
}
VB.NET
Namespace Silv4.Company.View.ModelVew.Model
Public Interface IEmployee
Sub GetAllEmployees()
'The Following event is used for notification
'for the Operation completed by the ViewModel.
'This is REquired because the SIlverlight applications
'makes async call to service.
Event GetAllEmployeesCompleted As EventHandler(Of EmployeeOperationsEventArgs)
End Interface
End Namespace
The interface contains a method called ‘GetAllEmployees’ which is used to make a call to the WCF service using proxy. The event ‘GetAllEmployeeCompleted’ is used for notification, when the fetch of the data is completed. This event is required because Silverlight makes an asynchronous call to WCF services.
Step 11: To the Model folder, add a new class and name it as ‘EmployeeModel’. This class implements ‘IEmployee’. This class makes a call to the WCF service using proxy. The implementation is as shown below:
C#
using Silv4.Company.View.ModelVew.MyRef;
namespace Silv4.Company.View.ModelVew.Model
{
//This class is responsible for making call to the Service and perform Data operations
public class EmployeeModel : IEmployee
{
ServiceClient Proxy;
Employee[] arrEmp;
public EmployeeModel()
{
Proxy = new ServiceClient();
}
public void GetAllEmployees()
{
Proxy.GetAllEmployeesCompleted += new EventHandler<GetAllEmployeesCompletedEventArgs>(Proxy_GetAllEmployeesCompleted);
Proxy.GetAllEmployeesAsync();
}
void Proxy_GetAllEmployeesCompleted(object sender, GetAllEmployeesCompletedEventArgs e)
{
if (e.Result != null)
{
arrEmp = e.Result;
//Raise The event
GetAllEmployeesCompleted(this, new EmployeeOperationsEventArgs(arrEmp));
}
}
public void CreateEmployee()
{
throw new NotImplementedException();
}
public event EventHandler<EmployeeOperationsEventArgs> GetAllEmployeesCompleted;
public event EventHandler NewEmployeeCreated;
}
}
VB.NET
Imports Silv4.Company.View.ModelVew.MyRef
Namespace Silv4.Company.View.ModelVew.Model
'This class is responsible for making call to the Service and perform ‘Data operations
Public Class EmployeeModel
Implements IEmployee
Private Proxy As ServiceClient
Private arrEmp() As Employee
Public Sub New()
Proxy = New ServiceClient()
End Sub
Public Sub GetAllEmployees()
AddHandler Proxy.GetAllEmployeesCompleted, AddressOf Proxy_GetAllEmployeesCompleted
Proxy.GetAllEmployeesAsync()
End Sub
Private Sub Proxy_GetAllEmployeesCompleted(ByVal sender As Object, ByVal e As GetAllEmployeesCompletedEventArgs)
If e.Result IsNot Nothing Then
arrEmp = e.Result
'Raise The event
RaiseEvent GetAllEmployeesCompleted(Me, New EmployeeOperationsEventArgs(arrEmp))
End If
End Sub
Public Sub CreateEmployee()
Throw New NotImplementedException()
End Sub
Public Event GetAllEmployeesCompleted As EventHandler(Of EmployeeOperationsEventArgs)
Public Event NewEmployeeCreated As EventHandler
End Class
End Namespace
The ‘GetAllEmployee()’ method makes an asynchronous call to the WCF service. When the call is completed from the Model to the WCF service, the ‘GetEmployeeCompleted’ event is raised. The argument to this event is the result returned by WCF service (marked in bold italics).
The above class represents implementation of the Model class. One thing I would like to tell you is to keep things simple, the above class does not include any failure or exception condition. So you can think of implementation of an error condition. Also I haven’t included the ‘CreateEmployee()’ method, you can do that also.
Step 12: In the ViewModel folder, add a class and name it as ‘’EmployeeViewModel . This class is used as a bridge between View and Model class. This class also defines Events which are used to receive notification from the Model and fire on the View so that data can be displayed. The implementation of the class is as shown below:
C#
using Silv4.Company.View.ModelVew.MyRef;
using Silv4.Company.View.ModelVew.Model;
using System.Collections.ObjectModel;
namespace Silv4.Company.View.ModelVew.ViewModel
{
//The class Makes the use of the EmployeeModel class
//by using the IEmployee interface it subscribe to the Model class
//to perform operations.
//This class makes use of events for the notification to UI.
public class EmployeeViewModel
{
IEmployee empModel;
//The important here is that, declare
//collection type so that, it will
//contain collection result so that
//it will be made available to View
ObservableCollection<Employee> allEmployees = new ObservableCollection<Employee>();
public ObservableCollection<Employee> AllEmployees
{
get { return allEmployees; }
}
//Now you need to declare events.
//These events will receive notification form
//Model and fire on the view
public event EventHandler GetAllEmployeeView;
public event EventHandler NewEmployeeCreatedView;
//This is used for Xaml binding in View
public EmployeeViewModel()
: this(new EmployeeModel())
{
}
public EmployeeViewModel(IEmployee eModel)
{
empModel = eModel;
empModel.GetAllEmployeesCompleted += new EventHandler<EmployeeOperationsEventArgs>(eModel_GetAllEmployeesCompleted);
}
//This will fire an event on UI thread (View)
void eModel_GetAllEmployeesCompleted(object sender, EmployeeOperationsEventArgs e)
{
Application.Current.RootVisual.Dispatcher.BeginInvoke(() =>
{
allEmployees.Clear();
foreach (Employee emp in e.AllEmployees)
{
allEmployees.Add(emp);
}
//Raise event of completion
if (GetAllEmployeeView != null)
{
GetAllEmployeeView(this, null);
}
}
);
}
//Make call to Method in the Model Class
public void GetAllEmployees()
{
empModel.GetAllEmployees();
}
}
}
VB.NET
Imports Silv4.Company.View.ModelVew.MyRef
Imports Silv4.Company.View.ModelVew.Model
Imports System.Collections.ObjectModel
Namespace Silv4.Company.View.ModelVew.ViewModel
'The class Makes the use of the EmployeeModel class
'by using the IEmployee interface it subscribe to the Model class
'to perform operations.
'This class makes use of events for the notification to UI.
Public Class EmployeeViewModel
Private empModel As IEmployee
'The important here is that, declare
'collection type so that, it will
'contain collection result so that
'it will be made available to View
Private allEmployees_Renamed As New ObservableCollection(Of Employee)()
Public ReadOnly Property AllEmployees() As ObservableCollection(Of Employee)
Get
Return allEmployees_Renamed
End Get
End Property
'Now you need to declare events.
'These events will receive notification form
'Model and fire on the view
Public Event GetAllEmployeeView As EventHandler
Public Event NewEmployeeCreatedView As EventHandler
'This is used for Xaml binding in View
Public Sub New()
Me.New(New EmployeeModel())
End Sub
Public Sub New(ByVal eModel As IEmployee)
empModel = eModel
AddHandler empModel.GetAllEmployeesCompleted, AddressOf eModel_GetAllEmployeesCompleted
End Sub
'This will fire an event on UI thread (View)
Private Sub eModel_GetAllEmployeesCompleted(ByVal sender As Object, ByVal e As EmployeeOperationsEventArgs)
'Raise event of completion
Application.Current.RootVisual.Dispatcher.BeginInvoke(Function() AnonymousMethod1(e))
End Sub
Private Function AnonymousMethod1(ByVal e As EmployeeOperationsEventArgs) As Boolean
allEmployees_Renamed.Clear()
For Each emp As Employee In e.AllEmployees
allEmployees_Renamed.Add(emp)
Next emp
RaiseEvent GetAllEmployeeView(Me, Nothing)
Return True
End Function
'Make call to Method in the Model Class
Public Sub GetAllEmployees()
empModel.GetAllEmployees()
End Sub
End Class
End Namespace
The event notification method i.e. eModel_GetAllEmloyeesCompleted, fires an event on the View and inserts all the fetched data from the Model into the Observable Collection. This raises the event GetAllEmployeeView which is used to notify to the View.
Build the project and make sure that it is error free.
Creating Silverlight View
In this step, we will create a Silverlight View.
Step 13: To the solution, add a new Silverlight application and name it as ‘SILV4_ClientApplication’. To this project, add a reference to ‘Silv4.Company.View.ModelVew’.
Step 14: In the Silverlight application, add a new folder and name it as ‘Views’. In this folder, add a new Silverlight UserControl and name it as ‘viewGetAllEmployees’. Using the Drag-Drop features of VS 2010 Silverlight designer, add a Button and a Datagrid to the designer.
Step 15: In viewGetAllEmployees.xaml.cs, write the following code:
C#
EmployeeViewModel empViewModel;
public viewGetAllEmployees()
{
InitializeComponent();
empViewModel = new EmployeeViewModel();
empViewModel.GetAllEmployeeView += new EventHandler(empViewModel_GetAllEmployeeView);
}
void empViewModel_GetAllEmployeeView(object sender, EventArgs e)
{
ObservableCollection<Employee> Employees = empViewModel.AllEmployees;
dgEmp.ItemsSource = Employees;
HtmlPage.Window.Alert("Data Fetched..");
}
private void btnLoadEmployee_Click(object sender, RoutedEventArgs e)
{
empViewModel.GetAllEmployees();
}
VB.NET
Private empViewModel As EmployeeViewModel
Public Sub New()
InitializeComponent()
empViewModel = New EmployeeViewModel()
AddHandler empViewModel.GetAllEmployeeView, AddressOf empViewModel_GetAllEmployeeView
End Sub
Private Sub empViewModel_GetAllEmployeeView(ByVal sender As Object, ByVal e As EventArgs)
Dim Employees As ObservableCollection(Of Employee) = empViewModel.AllEmployees
dgEmp.ItemsSource = Employees
HtmlPage.Window.Alert("Data Fetched..")
End Sub
Private Sub btnLoadEmployee_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
empViewModel.GetAllEmployees()
End Sub
The above code shows that on the View, event from the ViewModel class is raised. When the button is clicked, the View makes a call to the ViewModel class to the GetAllEmployee(). This method raises the event to which the View (UI) is subscribing. The data fetched from the ViewModel is notified to UI and bound with the DataGrid.
Step 16: Run the application and if everything’s ok, the following result will be displayed:
Conclusion: This article demonstrated how to build a Silverlight application that consumes a WCF service keeping minimum dependencies between the Model and View. This article does not use the MVVM approach. Check out the MIX session by Laurent to know more about building MVVM applications http://live.visitmix.com/MIX10/Sessions/EX14
The entire source code of this article can be downloaded over here
Update: Comments have been disabled for this article to avoid further confusion.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @
maheshdotnet or connect with him on
LinkedIn