Forward Visibilty - Code Blog

Saturday, September 5, 2009

Silverlight - Automated Deployment - use WCF with relative Path

This is a great trick. Stop using the config file automatically generated in for WCF client in Silverlight and just use a relative path. This makes it so you don't need different config files for each environment and open up that XAP file. In the code below the UIService is just the class that is generated by adding a service reference to WCF in silverlight. So easy, super useful.

void PageConstructor()
{
UIService.UIServiceClient myService=GetUIService();
myServices.Completed.... += CompletedEvent(....);
}

void PageLoad(....)
{
myService.Async...();
}

public static UIService.UIServiceClient GetUIService()
{
var uri = new Uri(Application.Current.Host.Source, "../SLServices/UIService.svc");
return new UIService.UIServiceClient("CustomBinding_IUIService", uri.AbsoluteUri);
}


Also read WCF is Singleton if you want to understand why I put this code in the constructor.

WCF Delegate in Silverlight 3.0

So it appears WCF in Silverlight operates like a singleton. This code below will actually fire the completed even 2 times, even though the async method was called once and the first service was disposed of.

void Page_Loaded(object sender, RoutedEventArgs e)
{
var svc= new UIService.UIServiceClient();
svc.GetXYZCompleted += GetXYZompleted;
svc=null;

var svc2= new UIService.UIServiceClient();
svc2.GetXYZCompleted += GetXYZompleted;
svc2.GetSpendDataAsync();
svc2=null;
}
Sure you can always just do a svc2.GetXYZCompleted -= GetXYZompleted; but it is just safer and cleaner code to put it in the constructor. Frequently it is not a problem to put it in the page load, because even your page load is only called one time. But if you use something like a tab control. Then each time you click on the tab the page load will get fired again. To be safe put them in the constructor, but remember you can't set break points on the constructor in Silverlight so debugging is a little more difficult.

Your code could look like this.
private void ConstructorCommon(MainPage mainPage)
{
InitializeComponent();
SetAllDelegates();
}

Serialization and Inheritance in C#

So there are many posts on serialization, but this code seems to work a little better :) I don't remember exact details, but let's just say it generically handles any types. And the best part it even works with inheritance. Just make sure you add the reference to the namespace System.Runtime.Serialization and put this code on your classes

   
[KnowType (typeof(Employee))] //Just examples of types that inherit from Person
[DataContract]
public class Person
{
[DataMember]
Public string FirstName {get;set}
Public string LastName {get;set}
}

.....
static void Main(string[] args)
{
var list = new List<person>();
list.Add(new Person() { FirstName = "Fred", LastName = "Flinstone" });
list.Add(new Person() { FirstName = "Barney", LastName = "Rubble" });
list.Add(new Employee() { FirstName = "Michal", LastName = "Cool" });
var ser=Serialize <list<person>>(list);
XmlDocument serialized= Deserialize<list<person>>(ser);
List<person> listOfPersons= object.Equals(des,list);
}

public static T Deserialize<t>(XmlDocument doc)
{
var xs = new DataContractSerializer(typeof(T));
object o = xs.ReadObject(new XmlTextReader(doc.OuterXml, XmlNodeType.Document, null));
return (T)o;
}

public static XmlDocument Serialize<t>(T obj)
{
var xs = new DataContractSerializer(typeof(T));
var ms = new MemoryStream();
try
{
xs.WriteObject(ms, obj);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw new ApplicationException(ex.Message);
}
ms.Flush();
ms.Position = 0;
var sr = new StreamReader(ms);
var doc = new XmlDocument();
doc.LoadXml(sr.ReadToEnd());
sr.Close();
ms.Close();
return doc;
}