Hidden Gems in Visual Studio 11 Beta - .NET Portable Class Libraries
I'm realizing there's a number of subtle but important new things in the next version of VS that streamline some previously difficult tasks. For example, there's the .NET Framework, but .NET is also in Silverlight, the Windows Phone, the Xbox, etc.
If you create a regular Class Library it has a single Target Framework. However, if you are doing a multi-platform application and you want to maximize your code reuse, you can run into trouble as you may not have all libraries available on the smaller platforms.
Thus, Portable Class Libraries were created. You can get Portable Class Libraries via an extension on Visual Studio 2010 or they are built into Visual Studio 11 Beta.
These Portable Class Libraries (PCLs) will generate a managed assembly that can be referenced by Windows Phone 7, Silverlight, the Microsoft .NET Framework and Xbox 360 platforms. This really helps to maximize reuse of code and reduce the number of projects in multi-targeted application solutions.
I talked about multi-targeting a little in the .NET Versioning and Multi-Targeting - .NET 4.5 is an in-place upgrade to .NET 4.0 post. Visual Studio is smart enough to tell you before compilation what APIs are available. The compiler knows and Intellisense knows. The Reference Assemblies down in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\ tell you a lot.
If you create a new Portable Class Library, right click on it and hit Properties. You can target specific frameworks and the build system and Intellisense will adjust. Some libraries are on some device. For example, XML Serialization isn't on the Xbox 360, but WCF is on the Windows Phone.
Bill Kratochvil has an article in MSDN Magazine that includes the source for a project that targets Windows Phone 7, Silverlight and WPF with shared libraries. David Kean has an article this month in MSDN Mag on how to Create a Continuous Client Using Portable Class Libraries.
Remember that Portable Class Libraries are constrained by design. You're targeting the lowest common denominator to maximize what you can use between projects. The MSDN article on Portable Class Libraries has a table that show what's available on each platform. You can do MVVM work across Windows, Metro style aopps, Silverlight and Windows Phone, for example.
Here's some good advice that David Kean sent me:
One thing [about] using portable [is that it] doesn’t mean you can’t use platform specific features, you just need to spend a little more time thinking about your dependencies. For example, instead of having a low level class that handles your persistence layer using the File APIs (which aren’t usable/available on Phone, Silverlight, etc), have it instead take work on an abstraction such as a stream, which these gets passed that from the platform specific project. Or have it call through an platform adapter (called out in my article), or inject the abstraction using your favorite IoC container (in my case Autofac, just published a portable version)
MSDN Help also shows what works with Portable Libraries as well so you're supported when looking at Help, Intellisense, and at Build time.
The BCL Blog mentioned that they are talking to the Mono guys about this as well. It'd be great to get Mono for Android and other frameworks as appropriate in here as well. I was excited to discover that this work was happening, even though it's been over a year in the making.
For folks like my friends at Rowi who have a great Windows Phone 7 application, or MetroTwit with a great WPF app, I wonder how Portable Class Libraries might change the architecture of their applications and enable cleaner builds and reuse scenarios they haven't thought of.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
It will be interesting to see if there is enough supported to enable established open source projects to run on top without much alteration: IoC tools, mapping tools, service clients, etc.
Has any major open source project actually moved to portable libraries yet? I'd like to know which ones and read a case study.
Regarding Caliburn.Micro...I'm not sure it would be worth the effort if only 30% of it could be put into a portable library. Plus, then I'd have to split it into multiple assemblies...and do some major re-architecture to work out the dependencies, just for the 30%. In the end, I don't think it would result in a net maintenance win for me, especially since I have so much conditional compilation code that is around sorting out the differences in Xaml implementations...which is definitely one reason why devs use Caliburn.Micro.
I like portable libraries. I hope it works for a lot of projects out there, but I don't think it will work for me. It seems like a rather intricate band-aid that's trying to fix up the lack of long-term vision for .NET that we've seen up to this point. Frankly, there was zero reason for API incompatibilities across Xaml implementations. But, now we are left with the pain...and who knows if portable libraries will ever be able to fix this up. Hopefully, the .NET team will learn something from this.
I'd be interested in reading your blog post but couldn't find it with some quick searching. Can you link us to it?
Rob,
I think in Caliburn's case the benefit of portable libraries would be for people using Caliburn as opposed to making it easier on you as Caliburn's developer. The portable part of Caliburn would be everything the ViewModels need to reference, so that people writing apps for different platforms could use the same portable ViewModels across all of them. The implementation Caliburn's conventions which bind the ViewModels to the UI would still be platform specific.
Of course that would be a lot of work, and until more people start trying to create portable ViewModels it's not certain that it would be a huge benefit. One thing that I think would be cool about it is that it might enable ViewModels to be portable to .NET 4. Most non-Caliburn ViewModels need ICommand which is only portable to .NET 4.5, but with Caliburn you just have an ExecuteCommand() method and a CanExecuteCommand property and you don't need ICommand at all.
Sorry, I didn't intend to link bait, especially when my post is only indirectly related to this one, which is why I left the link out. Since you asked for it, however, here it is: http://digitaltapestry.net/blog/waiting-for-nirvana. The post is basically about how one would want to use the portable library approach to solve the unit testing problem, and how we see the promise of it with VS11 but still can't fully get there. I'm actually doing it anway, switching back and forth between IDEs, with the hope (pretty much a given, but something theoretically could go wrong here) that when VS11 ships I will no longer have to deal with these issues.
I agree with most of what you said about Caliburn. However, I'm not sure I understand your comments about ICommand. ICommand has existed in .NET since the release of WPF in .NET 3. It's also existed in Silverlight for some time now (3? For sure in 4.). The issues surrounding ICommand, which still exist today, surround the View not the ViewModel (Silverlight and the Phone don't have ICommandSource and have only recently added the Command parameter to buttons, and only buttons). However, AFAIK, all MVVM libraries provide their own solutions to this problem.
Yes, that was probably an exaggeration. I'm not talking about things that were left out for size reasons. I'm talking about methods with different names, different signatures, or just different behavior even when everything on the surface looks the same. I'm talking about properties that moved from one type to another, different class hierarchies, etc. There are literally hundreds of things that were changed for no apparent reason...and I'm sure it had nothing to do with size. Those things are the ones which cause me so much pain.
@Daniel
I agree. But it's easier said than done. I haven't written off the possibility, but right now...I don't have time, and no one seems to be interested in helping with this sort of thing.
Also, apologies to everyone reading this. I didn't intend to start ranting here. Portable Libraries are actually a good thing and will probably work well for a large set of scenarios.
Also, there's a couple of things that make developing for Phone easier while using VS11:
- We've just release an update for Phone SDK (7.1.1) that enables you to install and use the SDK on Windows 8.
- We support VS2010 SP1 + VS11 sharing the same projects and solutions for projects that are supported in both. If you look at my article linked above, you'll see my solution layout that enables you to develop a Windows Phone and Metro app at the same time.
Rob: Thanks for the feedback. I'm yet to tackle Caliburn.Micro, but we had a go doing a private port of MVVMLight and got Laurent's projects down to 5 from 18. There's massive benefit in that - for the most part, you don't need to test the thing umpteen different times, less playing around with linked files and projects. Plus, you've now benefited those who've started using portable libraries for their apps. We're also not pretending that portable libraries are a replacement for platform-specific projects. For starters, your views between your Phone and tablet are likely to be different, and there's always going to be platform-specific features that you'll want to take advantage of or features that a platform lacks due to size, time or security restrictions. One thing we are looking at heavily though, is ways of enabling you to target additional features that may not be available everywhere within the same portable project.
With regards to the multi-assembly thing, is that because people hate referencing multiple assemblies? Does Nuget help with that? Would a way to reference and consume Caliburn as a single unit help?
Of course ICommand is available on .NET 4, but it is not available in a portable library that targets .NET 4. The reason for this is that it lives in a different assembly: PresentationCore.dll for .NET 4 and System.Windows.dll for Silverlight. Because .NET 4 had already shipped, we couldn't make ICommand portable between .NET 4 and Silverlight/Windows Phone. In .NET 4.5, we were able to make changes to make it portable.
If you are interested in some of the technical details behind how all of this works, this Channel 9 video is a great one to watch: .NET 4.5: David Kean and Mircea Trofin - Portable Libraries
That video also goes into the differences between adding portability after the fact (a "band-aid" as Rob says) versus how we are designing for portability for the future.
Oh yeah, and it also covers why we changed the reflection APIs (ie you have to call GetTypeInfo()) for Metro style apps, if you're interested in that. :)
Thanks for the video link. I'll check it out tomorrow.
Nuget would help with the multiple assembly issue, yes. But, don't assume that because you had moderate success with MVVMLight that the same would be true of Caliburn.Micro. They are two completely different creatures. For starters, I have a big dependency on System.Windows.Interactivity. That probably prevents moving to portable libraries itself. It would require...a massive refactoring to sort that out.
Ok. Let's not talk about Caliburn.Micro here anymore. Even I'm getting annoyed by hearing about it now ;) Anyone who wants to discuss further, please feel free to email me.
I'm really glad to hear that portability is being planned for in the future. I just wish it had been a priority from the beginning. I wish I could get back the time I lost. Honestly, I'm pretty beat down by the yearly platform changes that cause me to do massive porting work or altogether re-writes...just after I think I've got everything working again. The damage is done for me, as far as my desire to participate in .NET open source. Hopefully the work you are doing can prevent that from happening to others in the future.
The new SDK working on Windows 8 means little to me. I'm not targeting WinRT yet, so that's a non-issue. As for you're other point... that's pretty much what my blog post said you could do. Bounce back and forth between IDEs. It works, but it's painful, and I doubt most people will bother. Once we have a Phone SDK compatible with VS11 I expect the pain points to go away, at least for my use cases.
Daniel Plaisted,
Ahh, I understand what you were saying now. At least I understand why you were mentioning ICommand in .NET 4.5. I have to say I still don't understand why the portable library system couldn't work with .NET 4/3.5/3, though. What little I know about how the "magic" works comes from this series of blog posts: http://csharperimage.jeremylikness.com/2012/03/understanding-portable-library-by.html. ICommand still lives in different assemblies across desktop/silverlight, and WinRT creates an even bigger discrepency. Yet when you target .NET 4.5 you can reference ICommand across all of those platforms. I'll have to watch the video you and David both linked to see if I can grok the reasoning here. In any case, the problem today is mostly one of tooling. Even though the portable library system has been around for a while now, we're still not at a point of being able to really make use of it without some major pain points. Prior to VS11 it was with both the tooling and the (lack of) APIs and now it's mostly just a tooling problem. However, that's still a big barrier... one I hope is removed soon. :)
My port of Unity to the Portable Class Library compiled successfully under Metro WinRt but when I attempted to run the application that included the PCL. I would get a "Could not load file or assembly...". I blog on the topic => http://www.global-webnet.com/Blog/post/2012/01/08/METRO-Portable-Class-Library-=gt;-Could-not-load-file-or-assembly-SystemCore-Version=2050.aspx
It looks like you wrote that post before the Beta of VS Dev11 was released. Can you try again using the Beta? A lot of stuff changed between the Developer Preview and the Beta so the "Could not load file or assembly..." issue is probably fixed.
We had some discussions with the .NET team a year ago, but they didn't go anywhere.
Having the entire subset of the portable libraries in Mono is not the problem, the real problem is doing all the work to create the metadata files that will represent the various versions of the PLP out there ("WP7 and Silverlight" or "WP7 and Xbox" or "Just Xbox").
The simplest solution would be for Microsoft to give ECMA the binaries for the PLP so they become a standard, and we can reference and redistribute those libraries as part of Mono and Mono SDKs.
There are other advantages to contributing the PLP metadata profile to ECMA in addition to the redistribution, it would mean that ECMA would actually have a useful subset. The current subset that is standardized is a strange profile that is not really used in practice.
I've watched enough of the video to finally grok the issue here. You need changes in existing assemblies to do the type forwarding to handle the situations where types exist in different assemblies on different platforms. Without and update to older frameworks you can't do that, and updating those frameworks isn't without a whole set of problems.
BTW, I just realized that some of what I've been saying could have been misconstrued. I never thought there wasn't a reason behind why things are the way they are, I just didn't understand why. I'm also not complaining about the effort being made here. Far from it, I love what's happening. I'm just pointing out that we're in early days, still, and using portable libraries today isn't without some major pain points. It's not yet ready for wide adoption, and there's uncertainty as to when it will be. Tooling has to catch up, and it's not just VS11. AFAIK, Nuget also doesn't support portable libraries (would love to learn I'm wrong there, but there is an open issue on this topic, so I don't think I am).
Since I already a build script that happily compiles multiple versions for different platforms I've stuck with that.
Since a lot of people use JSON.NET, we'd really love to have a portable version so that people can build portable libraries on top of it. We'd be interested in hearing which APIs caused issues for you, and we'd be happy to help you create a portable version.
There's various reasons APIs might not be usable from portable libraries, David gives a good summary of them in his MSDN article (under "Converting Existing Libraries to PCLs").
Building multiple projects and going for code portability rather than binary portability allows you to use the common features of classes that have different levels of support in different environments, so you can use more of the Microsoft libraries.
There's a trade-off in complexity, of course, and if Portable libraries provide enough functionality for you, then they'll be simpler and therefore better. In our case, though getting rid of our multiple projects sounded great, in practice we'd have to give up too much, and it's worth being aware that for a bit more overhead, if you need it, you can have more portability options than the Portable libraries can deliver.
One trick that we've found useful to avoid maintaining lots of linked files between projects (which seems to be the way most people do code portability) is to put all the projects in one folder, declare one the master project in which it's OK to add source files through the Visual Studio UI, and use wildcards in the MSBuild of the other projects to pick up all source files under a certain folder. All it takes to update the other projects is to reload them, rather than having to manually link every file. This method may have been superceded by the Project Linker, but we haven't had time to check that out thoroughly yet.
Platform enlightenments explained
Making the core of Rx portable comes at a cost: the library can only rely on functionality in the intersection of all platforms targeted by the “Portable Library profile” we’re using.
...
To make this situation better, yet having a portable core, we added “platform enlightenments”. This innocent-looking System.Reactive.PlatformServices assembly plays a dual role. First of all, it provides platform-specific schedulers. Secondly, the (portable!) System.Reactive.Core assembly knows about its platform-dependent sibling and can check for its presence at runtime to get enlightened about the environment it’s running in.
...
Going forward, we’re engaging with the Portable Library BCL/CLR folks and the Windows Phone team to ensure an extended reach of our future portability story for Reactive Extensions.
Comments are closed.