This is Part 2 of my previous post "Passing parameters between Silverlight and ASP.NET – Part 1"
In my previous post, I have showed how to pass parameters between Silverlight and ASP.NET using Query Strings, Init Parameters and HtmlPage.Document
. These techniques are good as long as you are dealing with small amount of data and have certain limitation. There are some scenario where we have to pass large amount of data from ASP.NET to Silverlight and back from Silverlight to ASP.NET and our architecture design does not permit us to connect to Database directly from Silverlight component.
Today, I am going to show you how we can use Object Serialization to achieve the same. But remember, using this also poses some serious performance issues, so use this only when you really need this scenario. Internally, this technique uses the HtmpPage.Document
method only.
Just to give you a fair idea of how I can do this, I have created a sample Silverlight Application using Visual Studio Web Developer 2010, and added a class file called Employee.cs. This file just holds few entities of Employee
and EmployeeDetails
. Just to give you a feel of the actual scenario, I have created the Employee
and EmployeeAddress
as separate classes and written a method to return the sample data from these classes.
EmployeeAddress Class
public class EmployeeAddress
{
[XmlAttribute]
public string Address { get; set; }
[XmlAttribute]
public string City { get; set; }
[XmlAttribute]
public string PinCode { get; set; }
}
Employee Class
[XmlRoot("Employee")]
public class Employee
{
[XmlElement]
public string EmployeeName { get; set; }
[XmlElement]
public EmployeeAddress EmployeeAddresses { get; set; }
[XmlElement]
public int Age { get; set; }
public List<Employee> GetEmployeeData()
{
List<Employee> employees = new List<Employee>();
employees.Add(new Employee { EmployeeAddresses =
new EmployeeAddress { Address = "V.B.Layout",
City = "Bangalore", PinCode = "560076" },
Age = 33, EmployeeName = "Brij Mohan" });
employees.Add(new Employee { EmployeeAddresses = new EmployeeAddress {
Address = "Beauty Layout", City = "Delhi",
PinCode = "111111" }, Age = 33,
EmployeeName = "Arun Dayal Udai" });
employees.Add(new Employee { EmployeeAddresses = new EmployeeAddress {
Address = "Mumbai Filmcity Layout", City = "Mumbai",
PinCode = "444444" }, Age = 33, EmployeeName = "Sarosh Kumar" });
employees.Add(new Employee { EmployeeAddresses = new EmployeeAddress {
Address = "Dimna Road", City = "Jamshedpur",
PinCode = "831018" }, Age = 33,
EmployeeName = "Bharti Priyadarshini" });
return employees;
}
public string GetSerializedEmployeeData()
{
MemoryStream mem = new MemoryStream();
System.Xml.Serialization.XmlSerializer xs =
new XmlSerializer(typeof(List<Employee>));
mem.Seek(0, SeekOrigin.Begin);
xs.Serialize(mem, GetEmployeeData());
byte[] data = mem.GetBuffer();
string xmlString = Encoding.UTF8.GetString(data, 0, data.Length);
return xmlString;
}
public List<Employee> GetDesializedEmployeeObject(string xmlData)
{
StringReader sr = new StringReader(xmlData);
XmlSerializer xs = new XmlSerializer(typeof(List<Employee>));
object employees = xs.Deserialize(sr);
return (List<Employee>)employees;
}
}
In the employee
class above, I have also written few helper methods to Serialize and de-serialize the objects, using XMLSerializer
.
Now coming back to the code behind of my default.aspx page, here I am only trying to simulate the actual scenario. On Page load, I am getting my dummy data and putting this data into a Hidden Filed. In actual environment, you may get this data from database and then put this into some hidden field.
protected void Page_Load(object sender, EventArgs e)
{
Employee emp = new Employee();
txtValue.Text = HttpUtility.HtmlEncode(emp.GetSerializedEmployeeData());
}
You may notice that I have used HttpUtility.HtmlEncode
, this is very important because we are passing XML Data during Postbacks
, failing to use this may give you the following error, which you may not like to see.
Server Error in '/' Application
A potentially dangerous Request.Form value was detected from the client (txtValue="<?xml version="1.0"?...").
OK, now my ASP.NET is ready to send data to Silverlight Control, it's now Silverlight's turn to get this data and parse it into Silverlight recognized format which Silverlight controls will understand.
First, I am adding the same employee
class to Silverlight project for deserializing the received serialized data from ASP.NET. To avoid duplication of data, I am adding the same class file to my Silverlight Project using Add as Link option from file dialogue.
First, right click your Silverlight Project and Select Add –> Existing Item.
Now, locate your Employee.cs file from the ASP.NET website project, and select Add As Link option from Add. This will basically create a shortcut to Employee.cs from your ASP.NET Application to your Silverlight Project. Basically both are same copy, so before you make any ASP.NET only specific changes to this file, make sure this should compile in your Silverlight application too, or vice versa.
Now once the shortcut of the Employee
is created in your Silverlight Application, we can use this class just like the normal class file. Now coming back to my Silverlight Application, open the MainPage.xaml, open the XAML View. To display the data, I have added a DataGrid
and ListView
of the Address
Item on the XAML Page.
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid AutoGenerateColumns="False"
Height="200" HorizontalAlignment="Left" ItemsSource="{Binding}"
Name="employeeDataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top" Width="361"
SelectionChanged="employeeDataGrid_SelectionChanged">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="ageColumn"
Binding="{Binding Path=Age}" Header="Age"
Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="employeeNameColumn"
Binding="{Binding Path=EmployeeName}"
Header="Employee Name" Width="SizeToHeader" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<Grid x:Name="employeeDetailList"
HorizontalAlignment="Left" Margin="454,19,0,0"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<sdk:Label Content="Address:"
Grid.Column="0" Grid.Row="0"
HorizontalAlignment="Left"
Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="0" Height="23"
HorizontalAlignment="Left"
Margin="3" Name="addressTextBox"
Text="{Binding Path=EmployeeAddresses.Address, Mode=TwoWay,
ValidatesOnExceptions=true, NotifyOnValidationError=true}"
VerticalAlignment="Center" Width="120" />
<sdk:Label Content="City:" Grid.Column="0"
Grid.Row="1" HorizontalAlignment="Left"
Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="1" Height="23"
HorizontalAlignment="Left"
Margin="3" Name="cityTextBox"
Text="{Binding Path=EmployeeAddresses.City, Mode=TwoWay,
ValidatesOnExceptions=true,
NotifyOnValidationError=true}"
VerticalAlignment="Center"
Width="120" />
<sdk:Label Content="Pin Code:"
Grid.Column="0" Grid.Row="2"
HorizontalAlignment="Left"
Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="2" Height="23"
HorizontalAlignment="Left"
Margin="3" Name="pinCodeTextBox"
Text="{Binding Path=EmployeeAddresses.PinCode, Mode=TwoWay,
ValidatesOnExceptions=true,
NotifyOnValidationError=true}"
VerticalAlignment="Center"
Width="120" />
</Grid>
</Grid>
In the code behind of MainPage.xaml, I have just added a few lines of code to load and bind the data from the ASP.NET page hidden field where we have kept our employee
Serialized data.
public partial class MainPage : UserControl
{
List<Web.Employee> employees = null;
public MainPage()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
var result = HttpUtility.HtmlDecode(HtmlPage.Document.GetElementById(
"txtValue").GetProperty("value").ToString());
SLAppCommunication.Web.Employee employee = new Web.Employee();
employees = employee.GetDesializedEmployeeObject(result.ToString());
employeeDataGrid.ItemsSource = employees;
}
}
private void employeeDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Web.Employee emp = ((DataGrid)sender).SelectedItem as Web.Employee;
employeeDetailList.DataContext = emp;
}
}
Here after, the Load
event of Silverlight Control I am reading the Data from the HTML Page textbox and then using HttpUtility.HtmlDecode
to decode the Encoded string
from the textbox
. This will give me the actual Serialized String
. Now since we want our data into an Object
format, so we are actually doing the reverse of what we already did in ASP.NET application. We are going to pass this XML Data into our function GetDesializedEmployeeObject
- this function will basically return me the List<Employee>
which we can directly bind to our DataGrid
control. Now let's run the application.
Ok, so this gives me all the data which we have created in our ASP.NET application. I have just added an employeeDataGrid_SelectionChanged
event so that when we select any rows in our Grid, it displays the detailed information of the same. And yes, using this method, we can avoid any calls to DB directly from Silverlight component. Here, Silverlight is just a component plugged into our ASP.NET page container.
Hope you liked this post, to get the proper formatted and running example of the source code, you can download it from here.