views:

368

answers:

4

Having just gone through a small experimenting session to try to see how much work it would take to bring our .NET class library, or at least portions of it, into Silverlight so that we can reuse business logic between the two worlds, I'm wondering if others have experience with this sort of thing.

The things I noticed, off the top of my head:

  • Lots of attributes missing (Browsable(false) for instance)
  • Lots of interfaces missing, or present, but empty (ICloneable is hidden, ITypedList missing)
  • Reflection differences (everything reachable needs to be public)
  • Some base class differences (no Component?)

So I'm wondering, is it really feasible for me to even look at this as a possibility?

I got the initial code running, but I had to just comment out a whole lot of the base functionality, mostly around handling lists since they are based on ITypedList and some base classes. Apparently I need to change to ObservableCollection in Silverlight, so a whole of of base-code needs to be changed in order to cope.

The actual business test class I created is 99.5% identical to the one I would've made for .NET, only some minor changes that would easily be usable in .NET as well, just not as I would've made it before looking at Silverlight. In other words, it looks feasible to share business logic, provided I can make the base classes compatible.

Just so I'm clear, what I'm talking about is that I would basically have two project files, one for .NET, and one for Silverlight, but the actual C# source code would be the same, shared between the two.

So does anyone have any experience with this? Any tips or guidelines?

Will it be worth it? It certainly warrants more looking into.

+3  A: 

It is definitely feasible.

It's done on a project here; the Silverlight project includes the C# ones, and there are some #IF statements handling some things (like log4net declarations), and other times things are just re-implemented. But in general, it's a huge win, and you should definitely attempt it (and certainly, we have, successfully).

-- Edit:

One point though, is that our OR/M (LLBLGen) didn't have inbuilt support for 'simple' objects to send down through Silverlight; but someone had written a plugin that handled it, which helped. So it may be worth considering what sort of DAL you're using, and how well it supports Silverlight.

Noon Silk
Ok, good, then you haven't come across any unsurmountable problems I assume. That's good to hear, then I'll certainly go ahead with this project.
Lasse V. Karlsen
Lasse: There are definitely some things missing; I can't recall from the top of my head, but some Reflection things, log4net, and so on. But it's definitely surmountable; (though, in VS2008 at least, there are some 'odd' things sometimes; when you use the 'Add as link' to add an existing class from the main project and change it, you have to open it (actually open it) via the Silverlight project before it recognises changes). Nevertheless, no soul-destroying issues :)
Noon Silk
Good. The thing that looks like the biggest issue is that I have to reimplement the base for our list classes, since we use lists a lot through our business logic, and we have some special list classes that know they're in a "business logic world", but looking at how ObservableCollection is used, it looks like it will do what we need, just have to change the code to cope with it. Our IoC container worked minus app.config configuration, but we won't be using that here anyway. Just wondered if anyone else had found any minefields that I couldn't see right away.
Lasse V. Karlsen
Lasse: Yes, you'll be able to make great use of ObservableCollection if you implement it within your own Collection properties (it's what we've done as well, and works great).
Noon Silk
We do our own code generation for data classes, but since SQL won't be executed in the client app anyway, we'll probably have to find a good way to transport those objects from the server.
Lasse V. Karlsen
Lasse: Indeed, that's what we use (some simple DTO's); of course all the calls to actually get the data (if required) is done via WebServices (not SQL on the client; that would be madness! :).
Noon Silk
No single answer seems more correct than any of the others here, accepting the one that was posted first.
Lasse V. Karlsen
+3  A: 

What I've done to facilitate this is:

  1. Frequent use of partial classes and #if !SILVERLIGHT to separate code into parts that Silverlight can handle.
  2. Use of code generation whenever possible. For example I've been experimenting with T4 templates that generate Silverlight equivalent attributes (DisplayAttribute instead of DescriptionAttribute for example)
  3. Whenever there's an interface/attribute that isn't implemented by Silverlight (such as IDeserializationCallback, ICloneable, INotifyPropertyChanging) I will create a dummy interface of the same name in the Silverlight application as long as I know that the fact that the implementation won't be used is not a problem.
  4. Finally, it's worth noting that in Silverlight 4, the assembly format does allow for sharing of binaries between Silverlight and .NET as long as there are no dependencies that Silverlight does not support.

One more note about the separate base classes - it may be worthwhile to create an abstract class that derives from ObservableCollection in Silverlight and BindingList (or whatever you're using in .NET) to minimize the impact on your typed collections.

UPDATE Today I was working on porting some .NET code to Silverlight that made heavy use of the System.Diagnostics API's like TraceSource, SourceSwitch, etc which do not exist in Silverlight. I created very minimal implementations of these in the Silverlight project and put them in the Einstein.Diagnostics namespace. In doing so I decided I needed a convention to easily identify code that was mimicking the .NET Framework vs. my own code. So I renamed the placeholder files to prefix them with an @ sign. I also prefixed the class names in those files as well. The nice thing about that is that the @ sign does not actually change their class names as far as the C# compiler is concerned. So @SourceSwitch still compiles to be Einstein.Diagnostics.SourceSwitch but in the code I can easily see something is up. I've also decorated these classes with a [SilverlightPlaceholder] attribute.

Josh Einstein
I will certainly look at fixing the dependency on ObservableCollection in a base class. Good to know about Silverlight 4, but unfortunately we probably cannot jump on that right away. Except for ITypedList I don't think any of the interfaces I encountered will pose a problem. As for our business logic classes, they're already built using a code generator, though it's our own tool, so anything we need to ask it to fix to get 100% compatibility is easily done. Thanks for your input! Just between the two answers I've gotten already I'm already relieved enough to go ahead with an initial update.
Lasse V. Karlsen
No single answer seems more correct than any of the others here, accepting the one that was posted first.
Lasse V. Karlsen
+2  A: 

I do this with protobuf-net, and I use a few approaches:

  • conditional compilation symbols in the project file to trigger subtle code-branches (yes, it isn't perfect, but it works)
  • re-introduction of some things; attributes might be an example here - your code can still use re-introduced attributes, even if the framework code doesn't; as a more extreme example of this, for compact framework I had to re-introduce a good chunk of the Expression API, which was fun
  • just drop some things ;-p

However if you are using ITypedList (which you mention), I can see that whole approach falling apart pretty messily; component-model is complex enough already, without having to force your way through the hacks too. It really depends quite how far you've gone down this road. Maybe 4.0 / dynamic will open up some of these options again?

Marc Gravell
Actually we use ITypedList because that gave us the ability to easily bind to most grid-components in use, with support for sub-properties. That is, I can bind to "Employee.FirstName", where Employee is a property on the objects in the list. I don't know yet if this is possible with ObservableCollection but if it is, we'll deal with the changes.
Lasse V. Karlsen
And the class library contains tons of stuff that is probably not going to be needed, and we'll use conditional compilation for lots of things as well. For instance, a Heap class I have, which we use, implements the non-generic collection interfaces like IList and ICollection, which I noticed was absent in Silverlight, so we'll just ignore those parts for Silverlight with some well-placed #if's.
Lasse V. Karlsen
Actually in Silverlight the data binding story is much more flexible than Windows Forms so scenario you described (binding to sub-properties) will not require you to jump through hoops like ITypedList. Have a look at the property path binding syntax and you'll see what I mean: http://msdn.microsoft.com/en-us/library/cc645024(VS.95).aspx
Josh Einstein
No single answer seems more correct than any of the others here, accepting the one that was posted first.
Lasse V. Karlsen
+2  A: 

One possible fix to your issue is to copy the missing code from the Mono project. Back in the day, I did a small project with the Compact Framework and it was missing the entire System.XLM namespace. I just copied the entire thing from Mono into my project, compiled it and it worked great with minimal changes, iirc.

AngryHacker
No single answer seems more correct than any of the others here, accepting the one that was posted first.
Lasse V. Karlsen