Patterns-Based Silverlight Development – Part I – Getting Started
During the summer I put together a session on Patterns-Based Silverlight Development that we delivered across the West Region as part of MSDN events. The session was structured around building a Silverlight application from the ground up that illustrated the use of the following design patterns: 1) Repository, 2) Pipeline, 3) Service Agent and 4) Model View ViewModel. The goal was not to build a final productionized version of the application, rather illustrate how one might take advantage of these patterns in a Silverlight application. I will follow the same plan here, albeit in more detail.
Environment and Demo Choices
- Visual Studio 2008 sp1
- .NET Framework 3.5 sp1
- Silverlight 3
- The Silverlight 3 tools for Visual Studio 2008 sp1
- The Silverlight 3 Toolkit – July 2009 drop
* There is no reason you wouldn’t be able to follow along using our free tools
Whenever you put together a sample application, you have to make some choices: Language, Web Services Stack, REST vs. SOAP, data access strategy, etc. The following is a listing of some of the choices I made for this sample to start with (I may swap in and out as things progress):
- Language: C#
- Data Access: LINQ to SQL – This was a random decision. I had done a bunch of work with the EF lately. Thought I’d give it a go. I may swap this layer out later for the EF when .NET 4 hits Beta 2
- Web Services: WCF, SOAP, New custom Silverlight binding
Setting up the Project
I set up Visual Studio to use solution folders to clearly illustrate what is server code and what is client code. Here is what it will look like eventually:
We are going to start with creating a blank solution and add the 2 solution folders. We will then add the HelpDesk.Data project to the Server solution folder.
- Create a blank solution
- On the File menu, select New and then click Project
- Under Project types, select Other Project Types and then select Visual Studio Solutions
- Select Blank Solution
- Name it HelpDesk
- Add the ‘Client’ and ‘Server’ solution folders
- Right-Click on the Solution
- Choose Add -> New Solution Folder -> Name it ‘Client’
- Repeat for ‘Server’
- Add the HelpDesk.Data class library
- Right-Click on the Server solution folder
- Choose Add -> New Project
- Under Windows -> Choose Class Library
- Name it HelpDesk.Data
- Delete Class1
I am using a VERY simple data model I crufted up. There is a Ticket table with a SeverityLevel Lookup table. See below:
Building the LINQ to SQL Model
I assumed that this part of the application would take under 5 minutes. As it turns out, that was a poor estimate. The issue I had surrounded serializing the generated L2S objects. It took me hours to realize that the Visual Studio designer did not support configuring the serialization in the way I needed it (at least I couldn’t figure it out). Truthfully, I could have skipped all of that pain and manually decorated the classes with the appropriate attributes up front, but I wanted to use the designer, if for no other reason than it would save me from re-decorating the classes every time I re-generated the classes. In the end, I was able to get partway there with the designer, but did have to make a change in the code, as well. Let’s walk through the process:
Adding the Tables to the Designer
- Add a LINQ to SQL named HelpDesk.dbml to the HelpDesk.Data project.
- Right-Click the HelpDesk.Data project –> Add –> New Item
- Choose Visual C# Items –> Data –> LINQ to SQL Classes
- Name it HelpDesk.dbml
- Add the ‘Ticket’ and ‘SeverityLevelLookup’ tables to the L2S designer
- From the ‘Server Explorer’, expand the Tables Node from the HelpDesk Database
- Drag the ‘Ticket’ and ‘SeverityLevelLookup’ tables onto the designer
- Make some simple adjustments to the model
- Rename the ‘SeverityLevel’ property to ‘Level’
- Rename the ‘SeverityLevelLookup’ Class to be ‘SeverityLevel’
Configure the Classes to be Serializable
By default the “Serialization Mode” for the Model is set to None:
What does that mean? Well, the default serializer for WCF is the DataContractSerializer. When it was first released (Fx 3.0), it required you to apply the DataContractAttribute to classes you wanted to serialize and to apply the the DataMemberAttribute to fields and properties you wanted to be serialized. WCF 3.5 sp1 lifted this restriction, allowing for the serialization for POCOs (Plain Old
C# CLR Objects). The Serialization Mode of None simply indicates that the designer will not add any DataContractAttributes or DataMemberAttributes to your classes or properties, respectively.
Do I really need to decorate my classes? I mentioned POCO serialization support. The reality is that if you have any relationships between your classes, you will need to decorate your classes. So the first step is to set this Serialization Mode to Unidirectional. Incidentally, you can click on the properties pane and then click on any white space in the designer to view the properties for the DataContext.
This means that the classes in the model will be decorated with a DataContractAttribute and some public properties will be decorated with a DataMemberAttribute. So which properties are decorated. To start with, all, public primatives will be decorated. What we have to now understand is which complex types will be decorated. This is where the term ‘Unidirectional’ takes on importance. Essentially, if you take a look at the generated classes, the SeverityLevel class contains a collection of Tickets and the Ticket class has a SeverityLevel object. Hopefully, you can see that if we serialized both sides of the relationship, we will create an endless loop. What Unidirectional then means is that we will support serializing one side of the relationship. By default, by choosing Unidirectional, we will serialize the parent class and the child collection. So, in this case, if we serialize the SeverityLevel class, we will by default serialize it’s collection of Tickets. Have a look at the designer (I clicked on the relationship arrow in the designer):
If you take a look at the HelpDesk.designer.cs file, you can see the actual code that gets generated.
Notice below that the Tickets collection is decorated with a DataMemberAttribute in the SeverityLevel class. Also notice that the SeverityLevel property is not decorated in the Ticket class.
This default behavior does not suit the needs of my application. It does not make sense to fetch a particular SeverityLevel (like Low, Medium or High) and with it a collection of Tickets. It does, however make sense to return a SeverityLevel type when fetching a Ticket. I need to change the direction of serialization. This is the point where spent all of my time. I was not able to find the appropriate settings in the designer to accomplish this task. Clearly, I could have simply taken the 30 seconds to delete the DataMemberAttribute above the Tickets property and added one above the SeverityLevel property. However, as I stated, every time the code was regenerated, I would have to remember to make this change. (*** It is highly likely that there is a way to do accomplish this in the designer. If you know how, please leave me a comment and I will update this post ***).
I was able to get partially there in the designer. By setting the Child property to ‘Internal’, I was able to prevent the Tickets collection from being decorated:
That left decorating the SeverityLevel property in the Ticket class. I simply did that manually. Now my LINQ to SQL model is ready to go.
Tomorrow I will build a repository layer and illustrate the value of that pattern.