Serializing and deserializing multiple generic collections using DataContractSerializer

The DataContractSerializer class is the successor of the XmlSerializer class. Introduced together with WCF. This one is also being used by WCF for serialization by default. You can of course always switch back to the good old XmlSerializer if you want to.

Anyway, if you wanted to serialize a collection with the XmlSerializer you had to use the XmlArrayAttribute

With the DataContractSerializer you get the CollectionDataContractAttribute class. Personally, I think that serializing a generic list via the DataContractSerializer is easier then with the XmlSerializer. Even with the DataContractSerializer I think they could have done it easier. You’ll see what I mean in a minute.

Let’s look at some code.

The example

The example will be a simple to-do list. You can specify a name, a due data and multiple tags.

Creating the necessary classes

   1: [DataContract(Name = "TodoList", Namespace = "http://www.mshelp.be")]

   2: public class TodoList

   3: {

   4:     [DataMember(Name = "Todos")]

   5:     public InternalTodoList Todo { get; set; }

   6:     public TodoList()

   7:     {

   8:         Todo = new InternalTodoList();

   9:     }

  10: }

  11: [DataContract(Name = "Todo")]

  12: public class Todo

  13: {

  14:     public Todo()

  15:     {

  16:         Name = String.Empty;

  17:         DueDate = DateTime.Now;

  18:         Tags = new TagList();

  19:     }

  20:     [DataMember(Name = "Name")]

  21:     public string Name { get; set; }

  22:     [DataMember(Name = "DueDate")]

  23:     public DateTime DueDate { get; set; }

  24:     [DataMember(Name = "Tags")]

  25:     public TagList Tags { get; set; }

  26: }

  27: [CollectionDataContract(ItemName = "Tag")]

  28: public class TagList : List<string> { }

  29:  

  30: [CollectionDataContract(ItemName = "Todo")]

  31: public class InternalTodoList : List<Todo> { }

The class TodoList will contain all the different todo’s and the Todo class contains the properties we already discussed. As you can see I also have two other classes. The TagList and the InternalTodoList, both marked with the CollectionDataContract attribute. You also see that these classes contain the generic lists. I did this because you can only add the CollectionDataContract attribute to a class or struct.

How to Serialize

As you can see I use the XmlDictionaryWriter class, which was also introduced with .NET 3.0.

   1: static void SerializeTodoList()

   2: {

   3:     var dcs = new DataContractSerializer(typeof(TodoList));

   4:     var ds = new FileStream(@"c:\MyTodoList.xml",FileMode.Create);

   5:     var xdw = XmlDictionaryWriter.CreateTextWriter(ds, Encoding.UTF8);

   6:     dcs.WriteObject(xdw, _myTodoList);

   7:     xdw.Flush();

   8:     someStream.Flush();

   9: }

How to Deserialize

For the desrialization we’ll use the XmlDictionaryReader class together with the DataContractSerializer.

   1: static void DeserializeTodoList()

   2: {

   3:     var dcs = new DataContractSerializer(typeof(TodoList));

   4:     var ds = new FileStream(@"c:\MyTodoList.xml", FileMode.Open);

   5:     var xdr = XmlDictionaryReader.CreateTextReader(ds, new XmlDictionaryReaderQuotas());

   6:     _myTodoList = (TodoList)dcs.ReadObject(xdr);

   7: }

Testing the code

Now for a simple test, let’s add some to-do’s. Don’t forget to define the _myTodoList, which is of course an instance of the TodoList class.

   1: static void InitTodoList()

   2: {

   3:     _myTodoList = new TodoList();

   4:     var todo1 = new Todo {Name = "Fix some issues"};

   5:     var tlist1 = new TagList {"fix", "issues"};

   6:     todo1.Tags = tlist1;

   7:     _myTodoList.Todo.Add(todo1);

   8:  

   9:     var todo2 = new Todo {Name = "Fix stuff"};

  10:     var tlist2 = new TagList {"fix", "stuff"};

  11:     todo2.Tags = tlist2;

  12:     _myTodoList.Todo.Add(todo2);

  13: }

The aforementioned code will generate the following XML.

   1: <TodoList xmlns="http://www.mshelp.be" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

   2: <Todos xmlns:a="http://schemas.datacontract.org/2004/07/CollectionDataContractAtt">

   3: <a:Todo>

   4: <a:DueDate>2009-06-20T15:19:57.196+02:00</a:DueDate> 

   5: <a:Name>Fix some issues</a:Name> 

   6: <a:Tags>

   7: <a:Tag>fix</a:Tag> 

   8: <a:Tag>issues</a:Tag> 

   9: </a:Tags>

  10: </a:Todo>

  11: <a:Todo>

  12: <a:DueDate>2009-06-20T15:19:57.201+02:00</a:DueDate> 

  13: <a:Name>Fix stuff</a:Name> 

  14: <a:Tags>

  15: <a:Tag>fix</a:Tag> 

  16: <a:Tag>stuff</a:Tag> 

  17: </a:Tags>

  18: </a:Todo>

  19: </Todos>

  20: </TodoList>

Hope this post was informative and if you have comments, remarks. Please let me know, any constructive feedback is welcome.

kick it on DotNetKicks.com Shout it Progg itvote it on WebDevVote.com

How to host a WCF service that uses Castle Windsor in a Windows Service

Setup

Currently I’m working on a web application project that also uses a WCF service for some operations. We are a big fan of using ALT.NET and are using Castle Windsor to do IoC (Inversion of Control)/Dependency Injection. The problem we were having was the small delay to start up the worker process in IIS. Which is not much you can do about within IIS. (As far as I know) Except for maybe making a wake up service that calls a simple method every x minutes. Just to keep the worker process alive.

If you don’t want to wake up the IIS worker process you can always host your WCF service in a managed application, a windows service for instance. This is something that is always running (if it automatically starts and is not stopped manually of course).

Castle Windsor

I’m not going to go into the details on why you should use Castle Windsor. Maybe another post. The main goal of this post is to get the WCF service that uses Castle Windsor hosted within the Windows Service. You’re maybe wondering..is this then so complex? Well it can give some problems. You will find many posts on the Internet concerning this matter. However many of these posts focus on hosting the WCF Service in IIS.

What I’m not going to discuss

Like I’m not going to go into the details of Windsor, I’m also not going to say how you create a WCF service or how you create a Windows Service. MSDN Library is a very handy resource for this.

Make Windsor work

To make Castle Windsor work you’ll need to do several things:

  • Reference the necessary libraries
  • Create a windsor.config or windsor.boo file (or both)
  • Create a windsor container
    • Add a facility
    • Load the config file
    • Register the container

One thing I’m going to say is that the Castle project has done a lot of effort into making it all work out. To make WCF and Windsor play nice together you have to use Castle.Facilities.WcfIntegration. This contains a factory for hosting the service, namely the ServiceHostFactory.

The difference between IIS and a managed application

The difference isn’t really all that big..you just have to do the proper config and make sure you do all the aforementioned prep work like you would do it when hosting the service via IIS.

When you would host the WCF service in IIS, you would do all the prep work in the global.asax. You don’t have this in a Windows Service or a console application. So just do this somewhere else. I’m not saying hosting the WCF service in IIS is bad..it has it’s advantages.

Let’s put this into practice

1) Reference the necessary libraries:

   1: using System;
   2: using Castle.Facilities.WcfIntegration;
   3: using Castle.Windsor;
   4: using Castle.Windsor.Installer;
   5: using Rhino.Commons;

2) Create a windsor.config or windsor.boo file (or both)

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <components>
   4:     <component id="MyWCFService"
   5:                    service="WCFServices.IMyWCFService, WCFServices"
   6:            type="WCFServices.MyWCFService, WCFServices">
   7:     </component>
   8:   </components>
   9: </configuration>

3) Create and register the WindsorContainer (IWindsorContainer). Normally you would do this in the global.asax. Now you need to define a method where you will do this part.

Now I’ll create a method that will create and register the necessary container. This method looks like this:

Declare a public WindsorContainer:

   1: IWindsorContainer Container { get; private set; }

Create the method, PrepWindsor (This will be called in our main method):

   1: Container = new WindsorContainer()
   2:       .AddFacility<WcfFacility>()
   3:       .Install(Configuration.FromXmlFile("Windsor.config"));
   4:  
   5: DefaultServiceHostFactory.RegisterContainer(Container.Kernel);

Now we have done all of the prepwork for Windsor. Now let’s create the ServiceHost. We will use the following class for this: Castle.Facilities.WcfIntegration.DefaultServiceHostFactory

   1: PrepWindsor();
   2:             
   3: using(var host = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory().CreateServiceHost(typeof(WCFServices.IMyWCFService).AssemblyQualifiedName,new Uri[0]))
   4: {
   5:      host.Open();
   6: }

As you can see I don’t create any endpoints programmatically. This happens via a config file that I have added. My App.config looks like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <system.serviceModel>
   4:     <behaviors>
   5:       <serviceBehaviors>
   6:         <behavior name="WCFServices.WCFServiceBehavior">
   7:           <serviceMetadata httpGetEnabled="true" />
   8:           <serviceDebug includeExceptionDetailInFaults="true" />
   9:         </behavior>
  10:       </serviceBehaviors>
  11:     </behaviors>
  12:     <services>
  13:           <service behaviorConfiguration="WCFServices.WCFServiceBehavior"
  14:         name="WCFServices.MyWCFService">
  15:         <endpoint address="WCFServices" binding="basicHttpBinding" contract="WCFServices.IMyWCFService">
  16:           <identity>
  17:             <dns value="localhost" />
  18:           </identity>
  19:         </endpoint>
  20:         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  21:         <host>
  22:           <baseAddresses>
  23:             <add baseAddress="http://localhost:8000/" />
  24:           </baseAddresses>
  25:         </host>
  26:       </service>
  27:     </services>
  28:   </system.serviceModel>
  29: </configuration>

Ok that should be it! Now you should be able to properly host the service in the managed application.

I would love to hear some feedback or if you have questions/remarks, please let me know.

kick it on DotNetKicks.com Shout it Progg it vote it on WebDevVote.com

Microsoft Surface on VTM

Yesterday we had elections here in Belgium and not that I’m really into politics I am into Microsoft and it’s technology. And yesterday I saw a nice application of one of Microsoft’s newest technologies, Microsoft Surface. VTM used Microsoft Surface with a very nice WPF application to show the results of the elections.

How to redirect your page to another page

Today I had to link a site to another site and it’s actually very easy. And probably everyone reading this blog will know this, but I didn’t know it  by heart. That’s why I’m posting it here for myself, for future reference.

Just add the following line with the correct page you want to link to in the HTML <HEAD> tag.

   1: <meta HTTP-EQUIV="REFRESH" content="0; url=http://www.pagetolinkto.com/index.html">