Friday, August 17, 2012

Portable Library Tools & Type Forwarding

This post is part of a series of posts where we are discussing Portable Class Library Tools. It allows same library to be targeting multiple frameworks including any combination of .net framework, Silverlight, Windows Phone, Metro and Xbox360 development. In the previous post we discussed how development environment determines what features set to support for a combination of selected environments. We also discussed how we can limit targeting frameworks on development machines.

Here we discussed how common feature set is available for development based on the target frameworks selected. We used a few interface and concrete types including ICommand, ObservableCollection<T> and INofityDataErrorInfo. Basically the availability of these types in a common codebase is in itself a great achievement. This is because these types are defined at different assemblies in different frameworks. Even if we keep the namespace similar then which implementation should be used by the compiler?

Let's first look at INotifyDataErrorInfo. This is available in Silverlight framework as follows:

The same interface is available in .net framework 4.5 at different location. Let's see the following definition:

Similar are the following examples:
  • ObservableCollection<T>
  • System.dll [.net Framework 4 & 4.5 Dev preview], System.Windows.dll [Silverlight]

  • ICommand
  • System.dll [.net Framework 4.5 Dev preview], PresentationCore.dll [.Net Framework 4], System.Windows.dll [Silverlight]
Now if we are targeting for .net framework 4.5 Developer's preview and Silverlight 4 then the observable collection type would be used from System.dll or System.Windows.dll?? In this post we will try to address how this is actually happening inside the hood of portable libraries.

In the previous post, we discussed about reference libraries and profiles. These reference libraries contain the metadata information for these types. The metadata information might be about where to get the actual definition of the type with necessary forwarding details. In order to look at the actual definition, we will be needing to disassemble a reference library. The reference libraries for .net portable can be found here:

The concept of Reference assemblies was introduced in .net framework 3.0. This is to provide design time version of these assemblies. At runtime the assemblies would be directly used from Global Assembly Cache. We have seen in the previous post how profiles are used for targeting a set of selected target frameworks.

As we have previously seen, portable libraries can only be referenced by any of the selected target frameworks specified during development of the portable library. When loaded at runtime it would be using libraries directly from the host framework inlcuding Silverlight and .net framework. So for the case of mscorlib, the library [mscorlib] would be used from "Reference Libraries" folder during development. At runtime, the host framework's version of mscorlib would be used. You might be wondering about the API differences and differences in Types' behaviors for different frameworks. Don't worry about it, some changes were made in .net framework 4 to support just that. You can find the details here:

Let's look at the following chart:

These are names of types and their relevant assemblies. Most of the types in .net framework are at the same assembly, yet they are supported for portable libraries for .net framework 4.5 and not supported for .net framework 4. That seems quite strange. If they can be used by one then why can't they be used by the other one?? The explanation should cover how type's locations in different assemblies in multiple target frameworks (including Silverlight & .net framework 4.5) is addressed. The whole idea is type forwarding. Please remember that this is not a new concept introduced by Microsoft but this has been there for a while, Portable Library Tools is just cashing into that feature.

Basically, a portable library would always refer a type from the same assembly. Now it would be loaded in a certain framework including Silverlight or .net frameworks (or any other) with the assembly with same identification (e.g. System.Windows.dll). Based on the reference information in portable library, the framework would access the referred type from the same assembly as specified by the portable library. Now it is the assembly's responsibility to either provide the type or direct to some other assembly in the framework as a guidance for the type's location by using TypeForwardedToAttribute. There would be different System.Windows.dll for Silverlight and .net framework 4.5 with different manifest information. In Silverlight this would be directly provided by System.Windows but in .net framework 4.5, System.Windows would redirect the request to System.dll for the types specified in the chart.

The above explanation answers both questions. First, since the portable library always access the types from the same assembly, there is no magic in the portable library itself to for redirection of type's assembly location. It is actually the framework where the assembly is loaded which helps the portable library finding the specified type using type forwarding. Second, since the assemblies with type forwarding information is not available in .net framework 4 [e.g. System.Windows.dll], we can't use types for multitargeting where they are coming from different assemblies. So this Type Forwarding assembly is kind of a mediator. When the mediator is not present, there can't be any portability.

If you are curious like me then you might want to look at the definition of the assembly [System.Windows.dll] in .net framework 4.5. Well we can use ILDASM to see the assembly manifest. Please specially focus on the forwarder attribute for class type being forwarded. Now where to get this type from?? This is specified as ".assembly extern System", which is just saying that, "Look at the definition of this type in System assembly.". This is from the folder [C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5] instead of any profile from .NetPortable folder.

Now let's have a look at our portable library to see how System.Windows is referenced. It is referenced as retargetable assembly, which means that it would be loaded based on the host framework [Silverlight, .net framework 4.X etc].

No comments: