15
votes

Object browser in Visual Studio 2012 offers two different component sets for Portable class libraries:

  • .NET Portable Subset
  • .NET Portable Subset (Legacy)

When I create Portable Class Library it uses .NET Portable Subset. What is the second set and how can I use it? It contains MEF which is not available in .NET Portable Subset.

2

2 Answers

32
votes

Yep this is confusing, and is basically because Object Browser doesn't have a good way (and we couldn't add a way in this version without a significant rewrite) to represent the portable subset.

To help shed some light on this, consider the following diagram:

API Intersection

The circles represent the API surface area (not to scale) of the respective platforms. In portable, we effectively expose the APIs that exist in the overlapped areas. For example, when targeting all three above, we let you build against the surface area where all three platforms intersect (ie the very center). When targeting Windows Store and .NET Framework, we let you build against the intersection where those two platforms intersect (ie the center and bottom right). Target more platforms and the available surface area you get to use is reduced, target less platforms and the surface area you get to use is increased. If you think about it, this makes sense, the more platforms that you combine the less they have in common.

How does this fit in with what you see in the Object Browser?

In the Object Browser, we don't have an easy way to expose those individual intersections (and when you factor in the number of platforms + individual versions, there's a lot!). So instead, what we did was to grab all the available surface area in portable (ie all the intersections combined), and instead expose that. This means that the Object Browser shows you a combination of all the APIs that we consider "portable" across all of the platforms.

That's why you see MEF. MEF is available when you target .NET Framework and Silverlight but as soon as you add Phone or Windows Store to your targets, you lose it because it's not supported on those platforms.

What's the difference between .NET Portable Subset and .NET Portable Subset (Legacy)?

In portable, we have two ways to enable portability depending on whether you are targeting what we call legacy platforms or new platforms.

For legacy platforms (Phone 7.x, SL4/5, .NET 4, Xbox), when we come up with the intersections between multiple platforms, we need to physically generate actual assemblies that represent the common APIs. For example, when you combine Windows Phone 7 and .NET Framework, we generate (these are generated on our side in Microsoft) an actual mscorlib, system, system.core, etc that contain the APIs that these share. This is not only very time consuming, it's also extremely problematic in that it can generate not very useful subsets. As an example, when we first generated the subset for the networking stack across the platforms, there wasn't even a way to create a common way to create a HttpWebRequest connection. This was because on the older platforms (for whatever reason) no one had thought about portability.

For new platforms (.NET 4.5, Windows Store, Phone 8), we took a step back and designed portability from the get go. Rather than attempt portability as an afterthought, we designed what we call contracts (basically assemblies) that represent a self-contained, unit of code that either a platform supports all of, or none of. This means that when you see "System.IO 4.0.0.0" on .NET Framework 4.5, it supports exactly the same APIs that you will see when you see it on Windows Phone 8. This makes portability very easy, rather than needing to generate custom assemblies to represent the intersection of a platform, we simply subset at the assembly boundary. For example, given a platform 1 that supports System.Runtime.dll, System.Reflection.dll and System.Reflection.Emit.dll and platform 2 that supports System.Runtime.dll and System.Reflection.dll. When you target these platforms in portable, we simply choose System.Runtime.dll and System.Reflection.dll. Long term this makes portability a lot easier to understand, as you can think in terms of assemblies instead of individual APIs.

The surface area (Mscorlib-based) that are exposed for legacy platforms are represented by .NET Portable Subset (Legacy), whereas for new platforms, this is represented by .NET Portable Subset.

When using portable, we attempt to hide these two surface areas, but under the covers we target your against the first or the second surface area depending on your target platforms.

This is a lot longer than I planned, but feel free to ask clarifying questions, I've been living and breathing this for the past 3 years, so I tend to skip over things without thinking about it.

0
votes

This was so much simpler in the olden days when it was just .NET Framework vs .NET Compact Framework, but Microsoft just had to add XNA/360, Silverlight, and Windows Phone in to the mix.

I can't find any official description of "Portable Subset (Legacy)" but the documentation about the "Portable Subset" excludes mentions of the Compact Framework, so my guess is that the "Legacy" subset refers to the Compact Framework if it's the case that the non-Legacy subset refers to XNA, SL and WP7.