With the release of Informant v0.1.5.0 today I wanted to take a minute and talk about some of the changes and challenges I faced with this iteration. Let me first tell you what my goal was with this iteration. I wanted to create a single code base that could be reused in the Windows Service world as well as in WPF4, Silverlight 4, and Windows Phone 7. The challenge was finding which kind of class library can be shared with other kinds of applications. I discovered that Silverlight 3 was the appropriate base library type to use. Any .NET solution can reference SL3 libraries. I hoped to be able to make all of my model objects in SL3 assemblies and share them across all applications. However, I ran into some show stoppers in namespace conflicts. The model objects would be used in WCF therefore they needed to have DataContract and DataMemeber attributes applied to them. The namespace System.Runtime.Serialization cannot be shared between SL3 and WPF4. I got the following exception when I tried this: “Could not load file or assembly ‘System.Runtime.Serialization, Version=18.104.22.168, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’ or one of its dependencies. The system cannot find the file specified.” WPF4 does not understand and is not compatible with this version of the SL3 framework. Super big bummer! This meant that I could only use Interfaces to enforce my model object APIs. Since I wanted consistency this is exactly what I did. Only one SL3 library is shared between all of the UI applications and the Windows Service.
The next hurdle was handling a WCF service reference that would work in all scenarios. I found that this was also not possible, or rather was not ideal for my situation. I wanted my WPF4 application to be very rich and have have duplex channels which are not supported in SL3/4 or Wp7. This meant that every framework had to have it’s own non-reusable reference to the service. These references live in the DataProviders.[Framework] assemblies. Even though I know that the model objects coming from the service are implementing the Interfaces defined in the shared library, I cannot treat these objects as those Interfaces when they come out of the service. I must be able to do this in order for my UI, ViewModels, and other DataProvider dependent assemblies to be shared across frameworks. To overcome this I made a partial class for each model object coming from the service and had the partial I made implement the correct Interface. This caused two problems for me. First, the Interfaces were using IEnumerable<T> which is not supported in WCF. The models from WCF all use List<T> when they come across the wire. In order to solve this I had to tell WCF to change the names of the IEnumerable<T> properties when they were sent across the wire and I had to make each IEnumerable<T> property in the partial I made use the List<T> property from the WCF partial class as the backing field. This was preferred over changing the Interfaces to enforce desired behavior. Second, there was an error that said the WCF partial and the partial I made had difference base classes after I implemented the Interface. This was so very confusing, and it took me a while to figure out. Turns out Visual Studio 2010 (and perhaps prior versions) specify each model as inheriting from object.
public partial class Contact: object
This behavior is unnecessary and redundant since every object in C# already inherits from object by default. I had to go through the Auto Generated code and remove all explicit inheritance from object. After I did this the application compiled just fine. Strangely enough, now whenever I update my service reference the explicit inheritance is added back in, but does not cause an error as it did the first time. While I’d love to understand what exactly was going on with the error, it seems to have resolved and is no longer causing me issues so I’ve stopped looking into it.
The UI presented the final difficulty. We use DelegateCommands all over in our ViewModels here at InterKnowlogy and I wanted to do the same in my VMs. The problem is the underlying implementation of the DelegateCommand class, and other classes, are so different that a VM specifically designed for each framework must exist. Much of the core functionality of each VM can be shared in a base VM but each framework must still have a specific VM implementation. The idea that VMs can be reused without modification is false, but a good deal of each VM can be shared, and that’s exactly what I took advantage of.
With all of that said and done I now have a working version of Informant for WPF4 referencing a Windows Service that is installed on the same machine. The service is required so users can close the application and leave their computer on and Informant will still send all of the desired SMS messages. The Wp7.5 (Mango) version is next on my plate. This version will require me to refactor the Windows Service to support a RESTful API. The service will also need to be hosted on a publicly accessible server. My goal is to enable Wp7 users to be able to send SMS messages to their contacts and contact groups. A SL5 version will then be next available on the same server as the RESTful service.
The ability to reference SL3 libraries in the different .NET frameworks has greatly decreased the amount of work required to develop a framework specific application that fulfills the same purpose. It’s quite amazing and awesome. However, a small word of caution should be made known. The new Windows 8 WinRT framework is NOT compatible with this pattern. Each library must be a WinRT library compiled against WinRT. So I will not be able to reuse the libraries, as is, in Windows 8 WinRT. This is a huge bummer, but makes sense as I’ve learned more about what WinRT really is.