Sunday, 27 February 2011

Silverlight and Wcf: custom property setters and prevent serialization of certain fields in generated classes

In this article I will show you how to obtain custom setter (and getter) methods and to avoid serialization of certain properties that are only required in the client part of your application.

This article is based on the Pete Brown's work:
so I suggest to read that article before this one.

The tecniche shown in the Pete's article allows me to customize the code in the getters and setters because in the Silverlight client code I will be using the Silverlight version of the class.

Let's see the class that we want to serialize down the wire:
   1 using System;
2 using System.Net;
3 using System.ComponentModel;
4
5 namespace MyClassLibrary
6 {
7 public partial class ClassToBeSerialized : SerialObject, INotifyPropertyChanged
8 {
9 private String _Name = "";
10 public String Name
11 {
12 get
13 {
14 return _Name;
15 }
16 set
17 {
18 _Name = value;
19
20 NotifyPropertyChanged("Name");
21 }
22 }
23
24 #region "PropertyChanged"
25
26 public event PropertyChangedEventHandler PropertyChanged;
27
28 private void NotifyPropertyChanged(String info)
29 {
30 if (PropertyChanged != null)
31 {
32 PropertyChanged(this, new PropertyChangedEventArgs(info));
33 }
34 }
35 #endregion
36 }
37 }


This class is edited in a Silvelight class library project. As explained in the Pete's article this class is also added as a link in a full Clr class library.

While the code of the web service will use the full Clr version of the class, the client will use the
version build with the Silverlight assemblies. And we tell to Silverlight to use its own version of the class setting the flag "Reuse Types in referenced assemblies" in the web service reference configuration.

In this way we don't lose the get and set sections of our properties that would have been lost if we would have choosed to don't reuse the types in the referenced assemblies.

Now we want to avoid the serialization of certain fields because we will use them only in the client code and we don't want to download or upload them by the wcf web service and waste bandwidth.

To achieve this we can extend the partial class ClassToBeSerialized in the Silverlight class Library in a different file but, this time, we won't link this file in the full Clr project.

Doing in this way the web service code won't see the properties added in the class extension and so these properties won't se serialized.

Let's see the partial class extension:

   1 using System;
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11 using System.ComponentModel;
12
13 namespace MyClassLibrary
14 {
15 public partial class ClassToBeSerialized : SerialObject, INotifyPropertyChanged
16 {
17 // if you add things that you want to see only within the Silverlight Client
18 // you can add them in an other partial class file.
19 // in this way the compiler doesn't complain about the System.Windows.* namespace
20 // and so you can use, for example, things like a MessageBox
21
22 private String _Surname = "";
23 public String Surname
24 {
25 get
26 {
27 return _Surname;
28 }
29 set
30 {
31 _Surname = value;
32
33 _Surname += " is a nice Surname!!!";
34
35 MessageBox.Show("Surname Changed!");
36
37 NotifyPropertyChanged("Surname");
38
39 }
40 }
41 }
42 }
43

You can see that I alter the Surname every time I set it adding " is a nice Surname!!!". This just to show that when I modify this property in the client code the setter is enabled and working.

You can also note that I can use a MessageBox because I can use the System.Windows.* namespaces since this file is not linked in the full Clr project and so it's not cross compiled.

Here I link a small project where you can see these few things together:

You can verify that the Surname isn't serialized or sent across the wire using Fiddler. Since Fiddler won't display localhost traffic you may want to follow these steps:
1) Start the project by pressing F5 (start debug).
2) Copy the address from your browser address bar.
3) Stop the debugging session.
4) Right click the web project in the Visual Studio Solution explorer panel.
5) Select Property Pages -> Start Options
6) Select Start url and paste the url copied from the address bar and add a dot after localhost.
You should obtain something like this
http://localhost.:<your port> /SilverAssemblySerialization.Web/SilverAssemblySerializationTestPage.aspx
7) Change the web service reference configuration in the Silverlight client project to point to the right url (please note the dot):
http://localhost.:<your port> /SilverAssemblySerialization.Web/Service.svc
With these steps Fiddler will monitor the traffic of the application and you will avoid cross domain exception since the wcf service and the Silverlight client binary share the same domain http://localhost.:<your port>

The application should have enough comments tho show what is going on.

No comments: