Portable Class Library – Gemeinsame Codebasis für verschiedene Microsoft Plattformen wie das .Net Framework, Silverlight, Silverlight für Windows Phone, Metro Style Apps für Windows 8 und die XBox 360.
Es fängt oft so an, man hat ein kleines Projekt z.B. eine Windows Anwendung. Nun möchte man den Benutzern ermöglichen die gleiche Funktionalität auch im Browser zu nutzen. Also wird ein weiteres Projekt, ein Webanwendung, erstellt und der gemeinsame Code wird in ein Drittes, ClassLibrary, Projekt ausgelagert und von den beiden Oberflächen-Projekten referenziert. Diese Trennung kann natürlich auch schon vorher vorhanden sein durch Einbezug von mehreren Anwendungsschichten oder aus anderen Gründen.
Dieses Vorgehen ist die erste Wahl wenn alle Projekte sich auf das gleiche Framework beziehen, alle kompilieren gegen .Net 4.0. Auch noch dann wenn Projekte sich aus Subsets zusammensetzen, es ist z.B. die Windowsoberfläche noch gegen die niedrigere .Net 2.0 Version kompiliert während die Weboberfläche gegen .Net 3.5 SP1 kompiliert ist. Dann wählt man für das ausgelagerte Projekt die größtmögliche gemeinsame Teilmenge aus um die Kompatibilität sicher zu stellen. Hier im Beispiel also .Net 2.0.
Was aber wenn sich keine gemeinsame Teilmenge ergibt, weil es sich um verschiedene Frameworks handelt. Man hat die beiden Oberflächen-Projekte die sich auf das .Net Framework beziehen und möchte zusätzlich eine App für das Windows Phone und eine Metro Style App für Windows 8 erstellen. Diese sollen alle auf die gleichen Grundfunktionen zurückgreifen können. Der Schritt über die ClassLibrary-Projektvorlage ist allerdings nicht mehr möglich, da das Windows Phone Projekt gegen das Silverlight for Windows Phone Framework kompiliert und die Metro-Style App gegen die Windows Runtime (RT).
Eine Möglichkeit das Vorhaben umzusetzen ist ein Projekt zu erstellen in dem der Code ausgelagert wird. Anschließend weitere Projekte hinzuzufügen für die Zielplattformen und die Codefiles nur zu verlinken. Der Vorteil liegt darin, dass die Codefiles nur einmal existieren aber für die entsprechende Plattform kompiliert werden. Außerdem lässt sich weiterer Plattformspezifischer Quellcode in den Projekten hinzufügen.
Eine neue elegante Möglichkeit, die zusammen mit dem Visual Studio 2012, derzeit noch als Release Candidate, installiert wird und für das Visual Studio 2010 nachinstalliert werden kann ist die „Portable Class Library“ kurz PCL.
Diese kann über die gleichnamige Projektvorlage für C# oder VB.Net angelegt werden und sieht auf den ersten Blick aus wie die ClassLibrary.
Anschließend wird nach den Zielframeworks gefragt. Dieser Dialog kann auch später noch über die Projekteigenschaften (Projektsettings) aufgerufen und geändert werden.
Diese Auswahl schränk das Subset an zur Verfügung stehenden Assemblies ein bzw. erweitert sie. Da die Gemeinsamkeiten einer .Net 4.0 und 4.5 Anwendung viel größer ist als z.B. in einer Windows Phone App und einer ASP.Net Anwendung hat man jeweils die gemeinsame Menge an Klassen aus der PCL zur Verfügung.
Das Beispielprojekt
Zu der oben angelegten Solution inklusive PCL kommen noch jeweils eine:
- Konsolenanwendung (.Net 4.5)
- ASP.Net Webanwendung (.Net 4.5)
- Windows 8 Metro Style App (WinRT)
- Windows Phone 7.1 App, befinden jedoch in einer seperaten Solution

In jeden dieser Clientprojekte kann normal auf unsere PCL (PersonCore) verwiesen und somit deren Funktionalität genutzt werden.
In der markierten Person-Klasse aus der Portable Class Library implementiere ich folgenden Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PersonCore
{
public class Person
{
public string Vorname { get; set; }
public string Nachname { get; set; }
public string Adresse { get; set; }
public DateTime Geburtstag { get; set; }
/// <summary>
/// Creates a dummy list
/// </summary>
/// <returns></returns>
public List<Person> GetPersons()
{
List<Person> liste = new List<Person>();
Random z = new Random();
liste.Add(new Person() { Adresse = "Bahnhofstr. 7", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Müller", Vorname = "Karl" });
liste.Add(new Person() { Adresse = "Schlossallee. 2", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Schmidt", Vorname = "John" });
liste.Add(new Person() { Adresse = "Bahnhofstr. 1", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Müller", Vorname = "Jack" });
liste.Add(new Person() { Adresse = "Waldweg. 88", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Müller", Vorname = "Lara" });
liste.Add(new Person() { Adresse = "Bahnhofstr. 76", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Hansen", Vorname = "Earl" });
liste.Add(new Person() { Adresse = "Bahnhofstr. 35", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Müller", Vorname = "Lisa" });
liste.Add(new Person() { Adresse = "Waldweg. 1", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Spettmann", Vorname = "Chris" });
liste.Add(new Person() { Adresse = "Bahnhofstr. 50", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Müller", Vorname = "Fiona" });
liste.Add(new Person() { Adresse = "Waldweg. 2", Geburtstag = DateTime.Now.AddYears(-z.Next(10, 80)), Nachname = "Spettmann", Vorname = "Charls" });
return liste;
}
/// <summary>
/// Gets all persons who are older than in the parameter
/// </summary>
/// <param name="yearsOld">Years</param>
/// <returns></returns>
public List<Person> GetPersons(int yearsOld)
{
var query = from p in GetPersons()
where p.Geburtstag.Alter() > yearsOld
orderby p.Nachname
select p;
return query.ToList();
}
public override string ToString()
{
return String.Format("{0}, {1} {2} - {3} Jahr alt.",
Nachname, Vorname, Adresse, Geburtstag.Alter().ToString());
}
}
}
Diese Sample Klasse ist sehr einfach gehalten und verfügt nur über vier Properties, eine Methode um eine Dummyliste zu generieren und eine um alle Personen die älter sind als der Parameter zurückzugeben. Zusätzlich habe ich dem Projekt eine Extension Klasse hinzugefügt die DateTime um die Methode “Alter” erweitert.
In den Clientprojekten wird nun einfach die Person Klassen instanziiert, eine Liste der Personen über ein bestimmten Alter abgerufen und angezeigt.
Dies sieht folgendermaßen aus:
Konsolenanwendung
static void Main(string[] args)
{
var persons = new Person().GetPersons(35);
foreach (var person in persons)
{
Console.WriteLine(person);
}
Console.Read();
}
ASP.Net Webanwendung
protected void Page_Load(object sender, EventArgs e)
{
var persons = new Person().GetPersons(35);
foreach (var person in persons)
{
RadioButtonList1.Items.Add(person.ToString());
}
}
Windows 8 Metro Style App und Windows Phone 7 App
ListBox in XAML
<ListBox x:Name="lstPersons" HorizontalAlignment="Left" Height="687" Margin="10,71,0,0" VerticalAlignment="Top" Width="1346">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Vorname}" Margin="0,0,15,0" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding Path=Nachname}" Margin="0,0,15,0" Grid.Column="1"></TextBlock>
<TextBlock Text="{Binding Path=Geburtstag}" Margin="0,0,15,0" Grid.Column="2"></TextBlock>
<TextBlock Text="{Binding Path=Adresse}" Grid.Column="3"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Datenabruf
private void btnFind_Click(object sender, RoutedEventArgs e)
{
lstPersons.ItemsSource = new Person().GetPersons(int.Parse(tbAlter.Text));
}
Wie?
Coole Sache, nun fragt man sich wie dies möglich ist. Ich habe die Vermutung, dass es mit dem Schlüsselwort “retargetable” im Manifest des Assembys zusammenhängt.
Über Korrektur bzw. Erläuterung oder Bestätigung würde ich mich freuen.
Ich hoffe ihr seid ebenso begeistert von der Portable Class Library wie ich es bin.
Im Visual Studio 2012 ist die PCL bereits enthalten, für VS2010 kann sie von der PCL Codeplex Seite heruntergeladen werden.
Die oben erstellten Beispiel Projekte können hier heruntergeladen werden:
Solution für VS2012 mit PCL, ASP.Net, Konsole und Metro Style App
Solution für VS2010 mit Windows Phone 7 Projekt
Ich wünsche euch viel Spaß beim Coden, gerade in der Zeit in der Windows 8 in den Startlöchern steht ist die PCL auf jeden Fall einen Blick Wert.
Chris Spettmann






