Tiefe Einblicke in CLR

Neue Funktionen und verbesserte Leistung in Silverlight 4

Andrew Pardoe

Eine der größten Änderungen in Silverlight 4 ist der Wechsel zu einer neuen CLR-Version für das Kernausführungsmodul. Von jeder .NET Framework-Version – von Microsoft .NET Framework 2.0 bis .NET Framework 3.5 SP1 – wird bisher dieselbe CLR wie im Kern verwendet. Bei .NET Framework 4 gibt es erhebliche Änderungen, darunter die Ausklammerung des einfach herunterladbaren Clientprofils sowie eine schnellere Startzeit dank der Optimierung des nativen Binärlayouts. Aber durch die hohe Anforderung, ein direktes Update mit hoher Kompatibilität zu entwickeln, sind immer Einschränkungen vorhanden gewesen.

Mit der Version .NET Framework 4 konnten wir signifikante Änderungen an der CLR selbst umsetzen und trotzdem eine gute Kompatibilität mit Vorgängerversionen gewährleisten. In Silverlight 4 wird die neue CLR als Basis für die CoreCLR verwendet, sodass alle Verbesserungen vom Desktop ins Web gelangen. Zu den wichtigsten Laufzeitoptimierungen zählen ein verändertes Standardverhalten des Garbage Collectors im Rahmen der Garbage Collection (GC) sowie die Tatsache, dass Silverlight Framework-Binärdateien nicht jedes Mal bei der Ausführung eines Silverlight-Programms per Just-In-Time-Methode (JIT) kompiliert werden. In den Basisklassen haben wir viele Verbesserungen vorgenommen, darunter Erweiterungen für den isolierten Speicher und Änderungen an System.IO, die einen Direktzugriff von Silverlight-Anwendungen, die mit erweiterten Berechtigungen ausgeführt werden, auf das Dateisystem ermöglichen.

Zunächst erhalten Sie einige Hintergrundinformationen zur Funktionsweise der CoreCLR-Garbage Collection.

Generationsbasierte GC

Für CoreCLR und Desktop-CLR wird dieselbe GC verwendet. Es handelt sich dabei um eine generationsbasierte GC, das heißt, ihre Operationen basieren auf der heuristischen Annahme, dass die zuletzt zugewiesenen Objekte mit hoher Wahrscheinlichkeit bei der nächsten Auflistungszeit zu „Abfall“ (Garbage) werden. Diese heuristische Annahme spiegelt sich im kleinen Rahmen wider: Direkt nach der Funktionsrückgabe kann nicht vom Programm auf die lokalen Objekte der Funktion zugegriffen werden. Die Heuristik gilt auch in größerem Maßstab: In der Regel werden von Programmen Objekte mit globalem Status gehalten, deren Lebensdauer der Ausführungszeit des Programms entspricht.

Normalerweise werden Objekte der jüngsten Generation zugewiesen, also der Generation 0. Dann werden Sie im Rahmen der GC (sofern sie diese überleben) zu älteren Generationen, bis die maximale (also älteste) Generation erreicht ist. In der aktuellen CLR-GC-Implementierung ist das Generation 2.

In der CLR-GC ist eine weitere Generation vorhanden, die als großer Objektheap (Large Object Heap, LOH) bezeichnet wird. Große Objekte, derzeit definiert als Objekte mit einer Größe von über 85.000 Byte, werden direkt im LOH zugewiesen. Die Garbage Collection für diesen Heap erfolgt zur selben Zeit wie für Generation 2.

Ohne eine generationsbasierte GC müsste der Garbage Collector den gesamten Heap überprüfen, um zu bestimmen, auf welchen Speicher zugegriffen werden kann und welche Speicherbereiche zu Abfall zählen. Erst danach kann der ungenutzte Speicher aufgelistet werden. Mit einer generationsbasierten GC hingegen ist es nicht nötig, jedes Mal den gesamten Heap zu prüfen. Da die Dauer einer solchen Collection direkt mit der Größe der aufzulistenden Generationen zusammenhängt, ist der Garbage Collector so optimiert, dass Objekte aus Generation 2 (und dem LOH) weniger häufig aufgelistet werden. Bei kleinen Heaps erfolgt die GC meist sofort, mit zunehmender Größe der Heaps nimmt auch die Dauer der GC zu. Somit ist es möglich, Garbage Collections für Generation 0 in Zentelmikrosekunden durchzuführen.

Bei den meisten Programmen sind Generation 2 und der LOH deutlich umfangreicher als Generation 0 und Generation 1, weshalb eine Prüfung des gesamten Speichers für diese Heaps mehr Zeit in Anspruch nimmt. Bedenken Sie auch, dass im Rahmen einer Garbage Collection der Generation 1 auch Generation 0 geprüft wird, und dass bei einer GC der Generation 2 alle Heaps aufgelistet werden. Aus diesem Grund wird eine Garbage Collection von Generation 2 auch als vollständige Auflistung bezeichnet. Weitere Informationen über die Leistung der verschiedenen Heap-Auflistungen finden Sie in der Kolumne „Tiefe Einblicke in CLR“ vom Oktober 2009 unter msdn.microsoft.com/magazine/ee309515.

Gleichzeitige GC

Der direkteste Algorithmus zum Ausführen einer Garbage Collection besteht darin, über das Ausführungsmodul alle Programmthreads anzuhalten, solange die GC ausgeführt wird. Wir bezeichnen diese Art der Collection als sperrende Auflistung. Damit kann die GC nicht verfügbaren Speicher verschieben, beispielsweise von einer Generation in die nachfolgende, oder sie kann verstreute Speichersegmente komprimieren, ohne dass vom Programm eine Änderung bemerkt wird. Bei einer Verschiebung des Speichers während einer Ausführung der Programmthreads sähe es für das Programm so aus, als wenn der Speicher beschädigt worden wäre.

Aber einige der Aufgaben während einer Garbage Collection wirken sich nicht auf den Speicher aus. Seit der ersten CLR-Version stellen wir einen GC-Modus bereit, mit dem gleichzeitige Auflistungen ausgeführt werden. Bei diesen Auflistungen wird ein Großteil der bei einer vollständigen GC anfallenden Aufgaben ausgeführt, ohne dass die Programmthreads für die gesamte Dauer dieser GC angehalten werden müssen.

Seitens der GC können zahlreiche Aufgaben ohne eine für das Programm sichtbare Statusänderung durchgeführt werden, beispielsweise wird sämtlicher Speicher, auf den der Zugriff durch Programme möglich ist, gefunden. Die Programmthreads werden weiter ausgeführt, während die Heaps von der GC geprüft werden. Vor dem Ausführen der tatsächlichen Auflistung muss von der GC nur geprüft werden, was während der Speicherprüfung geändert wurde. Wenn zum Beispiel durch das Programm ein neues Objekt zugewiesen wurde, muss dieses als aufrufbar gekennzeichnet werden. Anschließend fordert die GC das Ausführungsmodul zur Sperrung aller Threads auf – wie bei einer nicht gleichzeitig stattfindenden GC – und fährt fort, jeglichen Speicher zu prüfen, auf den zu diesem Zeitpunkt zugegriffen werden kann.

Hintergrund-GC

Die gleichzeitige GC bietet in den meisten Szenarios eine hervorragende Erfahrung, aber ein Szenario konnten wir doch erheblich optimieren. Sie wissen, dass der Speicher der jüngsten Generation oder dem LOH zugewiesen wird. Generation 0 und Generation 1 befinden sich in einem Einzelsegment, das wir als kurzlebiges Segment bezeichnen, weil es kurzlebige Objekte enthält. Ist das kurzlebige Segment gefüllt, können vom Programm keine neuen Objekte erstellt werden, da für sie kein Platz mehr im kurzlebigen Segment vorhanden ist. Folglich muss mit der GC eine Auflistung im kurzlebigen Segment durchgeführt werden, um Speicherplatz freizusetzen und die Zuweisung fortsetzen zu können.

Das Problem bei der gleichzeitigen GC liegt darin, dass während einer gleichzeitigen Auflistung keiner der genannten Punkte möglich ist. Vom GC-Thread kann während der Ausführung von Programmthreads kein Speicher verschoben werden (deshalb ist auch eine Verschiebung älterer Objekte in Generation 2 nicht möglich), und da bereits eine GC durchgeführt wird, kann keine kurzlebige Auflistung mehr ausgeführt werden. Jedoch muss durch die GC Speicherplatz auf dem kurzlebigen Segment freigesetzt werden, bevor das Programm fortgesetzt werden kann. Das ist eine Zwickmühle: Die Programmthreads müssen angehalten werden, und zwar nicht, weil die gleichzeitige GC für das Programm sichtbare Statusänderungen vornimmt, sondern weil das Programm keine weitere Zuweisung vornehmen kann. Wird durch die gleichzeitige GC festgestellt, dass das kurzlebige Segment keinen Platz mehr bietet, ermittelt die GC den gesamten verfügbaren Speicherplatz, hält dann alle Threads an und führt eine sperrende Komprimierung durch.

Das Problem erklärt die Motivation hinter der Entwicklung der Hintergrund-GC. Sie funktioniert insoweit wie die gleichzeitige GC, als dass hier die meisten Aufgaben einer vollständigen Auflistung in einem eigenen Thread im Hintergrund abgearbeitet werden. Der Hauptunterschied besteht darin, dass während einer Datenauflistung der vollständigen GC zusätzlich eine kurzlebige Auflistung stattfinden kann. Das bedeutet, das Programm kann weiterhin ausgeführt werden, wenn das kurzlebige Segment sich füllt. Die GC führt dann eine kurzlebige Auflistung durch, und alles verläuft wie erwartet.

Die Auswirkung der Hintergrund-GC auf die Programmwartezeit ist bedeutend. Wir konnten bei Ausführung der Hintergrund-GC deutlich weniger Pausen in der Programmausführung feststellen, und die auftretenden Pausen sind erheblich kürzer.

Die Hintergrund-GC ist der Standardmodus für Silverlight 4. Sie ist nur bei Windows-Plattformen aktiviert, da in OS X nicht die umfassende Betriebssystemunterstützung bereitgestellt wird, den die Garbage Collection für eine Ausführung im gleichzeitigen Modus oder im Hintergrundmodus benötigt.

NGen-Leistungsverbesserungen

Die Compiler für verwaltete Sprachen wie z. B. C# und Visual Basic produzieren keinen direkten Code, der auf dem Rechner des Benutzers ausführbar ist. Stattdessen wird eine Zwischensprache mit dem Namen MSIL (Microsoft Intermediate Language) verwendet, die zur Programmausführungszeit anhand eines JIT-Compilers in ausführbaren Code kompiliert wird.

Die Verwendung von MSIL bietet von der Sicherheit bis zur Portabilität viele Vorteile, aber JIT-kompilierter Code verlangt zwei Kompromisse. Erstens müssen zahlreiche .NET Framework-Codeabschnitte kompiliert werden, bevor die Hauptfunktion Ihres Programms kompiliert und ausgeführt werden kann. Somit muss Ihr Benutzer auf die JIT-Kompilierung warten, bevor das Programm gestartet wird. Zweitens muss jedweder verwendete .NET Framework-Code für jedes Silverlight-Programm kompiliert werden, das auf dem Computer des Benutzers ausgeführt wird.

NGen löst beide Probleme. Mit NGen wird .NET Framework-Code bei der Installation kompiliert, sodass er bereits in kompilierter Form vorliegt, wenn das Programm gestartet wird. Die mit NGen kompilierten Codeabschnitte können häufig von mehreren Programmen gemeinsam genutzt werden, wodurch das Workingset auf dem Computer des Benutzers beim Ausführen von zwei oder mehr Silverlight-Programmen beträchtlich reduziert wird. Weitere Informationen darüber, wie Startzeit und Workingset mit NGen verbessert werden, finden Sie in der Kolumne „Tiefe Einblicke in CLR“ vom Mai 2006 unter msdn.microsoft.com/magazine/cc163610.

Code von .NET Framework stellt einen großen Teil der Silverlight-Programme, es macht also einen erheblichen Unterschied in der Startzeit aus, wenn NGen in Silverlight 2 und 3 nicht verfügbar ist. Der JIT-Compiler braucht deutlich zu viel Zeit, um den Bibliothekscode im Startpfad jedes Programms zu optimieren und zu kompilieren.

Unsere Lösung des Problems besteht darin, dass der JIT-Compiler in Silverlight 2 und 3 keine Optimierung der Codegenerierung vornimmt. Der Code muss zwar immer noch kompiliert werden, aber da der JIT-Compiler einfachen Code erzeugt, nimmt dessen Kompilierung nicht sehr viel Zeit in Anspruch. Im Vergleich zu herkömmlichen Desktopanwendungen sind die meisten Programme, die für Webszenarios in umfangreichen Internetanwendungen geschrieben werden, recht klein und werden nur kurz ausgeführt. Noch wichtiger ist, dass es sich in der Regel um interaktive Programme handelt, das heißt, die meiste Zeit warten sie auf Benutzereingaben. Silverlight 2 und 3 zielen nun auf solche Szenarios ab, in denen eine schnelle Startzeit erheblich wichtiger ist als die Generierung von optimiertem Code.

Mit der Entwicklung von Silverlight Web Apps haben wir Änderungen vorgenommen, um die positive Erfahrung auch weiterhin zu gewährleisten. Beispielsweise werden in Silverlight 3 sowohl Installation als auch Ausführung von Silverlight-Anwendungen vom Desktop unterstützt. Normalerweise sind diese Anwendungen umfangreicher und führen mehr Aufgaben aus als die kleinen, interaktiven Anwendungen eines klassischen Webszenarios. In Silverlight selbst sind zahlreiche rechenintensive Funktionen hinzugekommen, so beispielsweise die Unterstützung der Fingereingabe für Windows 7 und eine umfassende Bildbearbeitung (z. B. wie auf der Bing Maps-Website). Für eine effiziente Ausführung aller beschriebenen Szenarios ist eine Codeoptimierung erforderlich.

Silverlight 4 bietet sowohl eine schnelle Startzeit als auch optimierten Code. Vom JIT-Compiler werden nun in Silverlight dieselben Optimierungen verwendet wie für .NET-Desktopanwendungen. Diese Optimierungen sind möglich, da wir NGen für Silverlight .NET Framework-Assemblys aktiviert haben. Bei der Installation von Silverlight wird automatisch der gesamte verwaltete Code, der zur Silverlight-Laufzeit benötigt wird, kompiliert und auf der Festplatte gespeichert. Wenn ein Benutzer das Silverlight-Programm ausführt, startet es, ohne dass eine Wartezeit aufgrund der Kompilierung von Framework-Code entsteht. Ebenso wichtig ist, dass der Code im Silverlight-Programm optimiert ist, sodass Ihre Programme schneller ausgeführt werden. Zudem kann Framework-Code von mehreren Silverlight-Programmen, die auf dem Computer des Benutzers ausgeführt werden, gemeinsam genutzt werden.

Während der Installation werden von Silverlight 4 native Abbilder für .NET Framework-Assemblys erstellt. Bei einigen Anwendungen ist ausschließlich die Leistung zur Startzeit wichtig. Nehmen Sie den Editor als Beispiel: Wichtig ist der schnelle Start des Programms; wenn Sie Daten über die Tastatur eingeben, ist die Ausführungsgeschwindigkeit irrelevant. Die Hauptsache ist, das Programm arbeitet schneller, als Sie tippen können. Für diese Art von Programm kann die Zeitspanne, die der JIT-Compiler zum Kompilieren des Startcodes der Anwendung benötigt, einen Leistungsabfall bedeuten. In Silverlight 4 starten die meisten Anwendungen zwischen 400 ms und 700 ms schneller, während der Ausführung ist eine Leistungsverbesserung von bis zu 60 Prozent zu verzeichnen.

Die Basisklassenbibliothek befindet sich im Kern der verwalteten APIs, die nun mit NGen in Silverlight 4 unterstützt werden. Nachfolgend stelle ich Ihnen die Neuerungen der Basisklassenbibliothek vor.

Neue Funktionen der Basisklassenbibliothek

Viele der neuen Erweiterungen der Basisklassenbibliothek in Silverlight 4 sind ebenfalls in .NET Framework 4 neu und bereits in diesem Kontext ausführlich beschrieben worden. Ich gebe Ihnen einen kurzen Überblick über die Neuerungen in Silverlight 4.

Verträge für Code bieten eine integrierte Möglichkeit, Vorbedingungen, Nachbedingungen und Objektinvarianten in Ihrem Silverlight-Code auszudrücken. Mit solchen Codeverträgen lassen sich Codeannahmen besser formulieren und Fehler frühzeitig finden. Die Codeverträge bieten zahlreiche weitere Vorteile. Weitere Informationen finden Sie in der Kolumne „Tiefe Einblicke in CLR“ geschrieben von Melitta Andersen vom August 2009 unter msdn.microsoft.com/magazine/ee236408, auf der DevLabs-Website „Code Contracts“ unter msdn.microsoft.com/devlabs/dd491992 und im Blog des BCL-Teams unter blogs.msdn.com/bclteam.

Zur Rückgabe mehrerer Werte von einer Methode werden meist Tupel verwendet. Sie werden häufig in funktionalen Sprachen wie F# und dynamischen Sprachen wie IronPython genutzt, sind aber auch mit Visual Basic und C# leicht und problemlos einsetzbar. Weitere Informationen über den Tupelentwurf finden Sie in der Kolumne „Tiefe Einblicke in CLR“ geschrieben von Matt Ellis vom Juli 2009 unter msdn.microsoft.com/magazine/dd942829.

Lazy<T> bietet einen einfachen Weg für die verzögerte Initialisierung von Objekten. Die verzögerte Initialisierung ist ein Mechanismus, den Anwendungen einsetzen, um das Laden oder Initialisieren von Daten so lange herauszuzögern, bis diese benötigt werden.

Die neuen numerischen Datentypen BigInteger und Complex sind im Silverlight 4-SDK in System.Numerics.dll verfügbar. BigInteger steht für „Arbitrary-Precision Integer“, also eine Ganzzahl mit beliebiger Genauigkeit, Complex steht für eine komplexe Zahl mit reellen und imaginären Komponenten.

Enum, Guid und Version unterstützen wie viele andere Basisklassenbibliothek-Datentypen nun auch TryParse. Somit lässt sich effizienter eine Instanz aus einer Zeichenfolge erstellen, die bei Fehlern keine Ausnahmen ausgibt.

Enum.HasFlag ist eine neue Hilfsmethode, um einfach prüfen zu können, ob für eine Flags-Enumeration ein Kennzeichen gesetzt ist. Kenntnisse über den Einsatz von bitweisen Operatoren sind hier nicht mehr nötig.

String.IsNullOrWhiteSpace ist eine weitere Hilfsmethode zum Bestimmen, ob eine Zeichenfolge den Wert null aufweist, leer ist oder nur Leerstellen enthält.

Überladungen des Typs String.Concat und Join arbeiten nun mit einem IEnumerable<T>-Parameter. Diese neuen Überladungen für String.Concat und Join ermöglichen eine Verkettung aller Auflistungen, die IEnumerable<T> implementieren, ohne dass diese Auflistungen zuerst in ein Array konvertiert werden müssen.

Stream.CopyTo ermöglicht das einfache Lesen aus einem Stream und Schreiben des Inhalts in einen anderen Stream in einer einzigen Codezeile.

Neben diesen neuen Features sind auch am isolierten Speicher Verbesserungen vorgenommen worden. Zudem können vertrauenswürdige Silverlight-Anwendungen nun über System.IO direkt auf Dateisystemsegmente zugreifen.

Verbesserungen am isolierten Speicher

Der isolierte Speicher ist ein virtuelles Dateisystem, das von Silverlight-Anwendungen zum Speichern von Daten auf dem Client verwendet werden kann. Weitere Informationen über isolierten Speicher in Silverlight finden Sie in der Kolumne „Tiefe Einblicke in CLR“ vom März 2009 unter msdn.microsoft.com/magazine/dd458794.

In Silverlight 4 besteht die bemerkenswerteste Verbesserung am isolierten Speicher im Leistungsbereich. Seit der Silverlight 2-Version haben wir viel Feedback von Entwicklern in Bezug auf die Leistung des isolierten Speichers erhalten. Wir haben bereits in Silverlight 3 einige Änderungen vorgenommen, die das Lesen von Daten aus dem isolierten Speicher erheblich verbessern. Für Silverlight 4 sind wir noch einen Schritt weiter gegangen: Wir haben die Leistungsengpässe aufgelöst, die Entwickler beim Schreiben von Daten in den isolierten Speicher bemerkten. Insgesamt ist die Leistung des isolierten Speichers in Silverlight 4 sehr stark optimiert.

Seitens der Entwickler wurde uns mitgeteilt, dass das Umbenennen und Kopieren von Dateien im isolierten Speicher sehr kompliziert ist. Um eine Datei umzubenennen, muss die ursprüngliche Datei manuell gelesen, dann eine neue Datei erstellt und der Inhalt hineingeschrieben werden. Abschließend wird die ursprüngliche Datei gelöscht. Ein Verzeichnis wird auf dieselbe Art und Weise umbenannt, erfordert aber zusätzliche Codezeilen. Dies gilt besonders, wenn das umzubenennende Verzeichnis Unterverzeichnisse enthält. Das funktioniert zwar, umfasst aber mehr Code, als eigentlich zu schreiben ist. Und es ist deutlich einfacher, das Betriebssystem anzuweisen, die Datei oder das Verzeichnis auf dem Datenträger umzubenennen.

In Silverlight 4 sind neue Methoden für die Klasse IsolatedStorageFile vorhanden, mit deren Aufruf Sie folgende Operationen in einer einzigen Codezeile ausführen können: CopyFile, MoveFile und MoveDirectory. In weiteren neuen Methoden werden zusätzliche Informationen über die Dateien und Verzeichnisse im isolierten Speicher bereitgestellt: GetCreationTime, GetLastAccessTime und GetLastWriteTime.

Des Weiteren ist die neue API IsolatedStorageFile.IsEnabled in Silverlight 4 verfügbar. In vorigen Versionen können Sie nur auf eine Weise herausfinden, ob der isolierte Speicher aktiviert ist: Sie versuchen, ihn zu verwenden. Wird die nachfolgend ausgegebene Ausnahme IsolatedStorageException abgefangen, ist der isolierte Speicher deaktiviert. Mit der neuen statischen Eigenschaft IsEnabled kann leichter bestimmt werden, ob der isolierte Speicher zur Verfügung steht.

Viele Browser (z. B. Internet Explorer, Firefox, Chrome und Safari) unterstützen inzwischen einen Modus für InPrivate-Browsen, bei dem Verlauf, Cookies und weitere Daten nicht gespeichert werden. Die Einstellungen zum privaten Browsen werden von Silverlight 4 respektiert. So ist es beispielsweise ausgeschlossen, dass Anwendungen auf den isolierten Speicher zugreifen und auf dem lokalen Computer Daten speichern, wenn der Modus für privates Browsen aktiviert ist. In einer solchen Situation wird von der Eigenschaft IsEnabled der Wert „False“ zurückgegeben. Jeder Versuch, auf den isolierten Speicher zuzugreifen, führt zur Ausnahme IsolatedStorageException. Das ist dasselbe Verhalten, als wenn der isolierte Speicher ausdrücklich vom Benutzer deaktiviert worden ist.

Dateisystemzugriff

Silverlight-Anwendungen werden in einem teilweise vertrauenswürdigen Sicherheitsbereich (Sandbox) ausgeführt. Der Sicherheitsbereich schränkt den Zugriff auf den lokalen Computer ein und platziert eine Reihe von Beschränkungen für die Anwendung. So wird verhindert, dass bösartiger Code Schaden anrichtet. Beispielsweise ist es teilweise vertrauenswürdigen Silverlight-Anwendungen nicht möglich, direkt auf das Dateisystem zuzugreifen. Falls von einer Anwendung Daten auf dem Client gespeichert werden sollen, ist dies nur im isolierten Speicher möglich. Der Zugang zum allgemeinen Dateisystem ist nur mithilfe von OpenFileDialog oder SaveFileDialog möglich.

In Silverlight 3 ist die Möglichkeit hinzugefügt worden, Anwendungen außerhalb des Browsers zu installieren und auszuführen. Damit eröffnen sich interessante Offlineszenarios – aber solche Anwendungen werden weiterhin in derselben Sandboxumgebung ausgeführt wie im Browser ausgeführte Anwendungen. Silverlight 4 ermöglicht es Anwendungen, die außerhalb des Browsers ausgeführt werden, sich selbst mit einer höheren Vertrauensstellung zu konfigurieren. Solche vertrauenswürdigen Anwendungen können einige der von der Sandbox nach der Installation vorgenommenen Einschränkungen umgehen. Beispielsweise können vertrauenswürdige Anwendungen auf Benutzerdateien zugreifen, das Netzwerk ohne domänenübergreifende Zugangsbeschränkungen nutzen, Benutzerzustimmungen und Initiierungsanforderungen umgehen und auf native Betriebssystemfunktionen zugreifen.

Installiert ein Benutzer eine Anwendung, die eine höhere Vertrauensstellung erfordert, wird die reguläre Installationsaufforderung durch eine Warnung ersetzt. Diese informiert den Benutzer darüber, dass die Anwendung Zugriff auf Benutzerdaten erhält und nur von vertrauenswürdigen Websites installiert werden sollte.

Vertrauenswürdige Anwendungen können die APIs in System.IO für den direkten Zugriff auf folgende Benutzerverzeichnisse im Dateisystem verwenden: Eigene Dateien, Eigene Musik, Eigene Bilder und Eigene Videos. Dateioperationen außerhalb dieser Verzeichnisse sind derzeit nicht zulässig und führen zur Sicherheitsausnahme SecurityException. Innerhalb dieser Verzeichnisse sind sämtliche Dateioperationen zugelassen, einschließlich Lese- und Schreibvorgängen. So kann zum Beispiel eine vertrauenswürdige Fotoalbum-Anwendung direkt auf alle Dateien im Verzeichnis „Eigene Bilder“ zugreifen. Eine vertrauenswürdige Anwendung für die Videobearbeitung kann einen Film im Verzeichnis „Eigene Videos“ speichern.

Es ist wichtig, Dateisystempfade für diese Verzeichnisse in den Anwendungen nicht mit einer Hartkodierung zu versehen, da diese Pfade je nach zugrunde liegendem Betriebssystem unterschiedlich sind. Die Dateisystempfade zwischen Windows und Mac OS X weisen kaum Ähnlichkeiten auf, aber auch zwischen verschiedenen Windows-Versionen sind erhebliche Abweichungen möglich. Um eine ordnungsgemäße und plattformübergreifende Funktionsweise zu gewährleisten, sollten die Dateisystempfade für diese Verzeichnisse mit System.Environment.GetFolderPath bestimmt werden. Mit folgenden Codeabschnitt wird der Dateisystempfad für das Verzeichnis „Eigene Bilder“ mit Environment.GetFolderPath abgerufen. Dann werden mit der Methode System.Directory.EnumerateFiles alle Dateien mit der Dateierweiterung .JPG in diesem Verzeichnis sowie allen Unterverzeichnissen ermittelt. Abschließend wird jeder Dateipfad einem ListBox-Element hinzugefügt:

if (Application.Current.HasElevatedPermissions) {
  string myPictures = Environment.GetFolderPath(
    Environment.SpecialFolder.MyPictures);
  IEnumerable<string> files = 
    Directory.EnumerateFiles(myPictures, "*.jpg", 
    SearchOption.AllDirectories);
  foreach (string file in files) {
    listBox1.Items.Add(file);
  }
}

Dieses Codebeispiel veranschaulicht, wie mit einer vertrauenswürdigen Anwendung eine Textdatei im Verzeichnis „Eigene Dateien“ des Benutzers erstellt wird:

if (Application.Current.HasElevatedPermissions) {
  string myDocuments = Environment.GetFolderPath(
    Environment.SpecialFolder.MyDocuments);
  string filename = "hello.txt";
  string file = Path.Combine(myDocuments, filename);

  try {
    File.WriteAllText(file, "Hello World!");
  }
  catch {
    MessageBox.Show("An error occurred.");
  }
}

Mit System.IO.Path.Combine wird der Pfad zum Verzeichnis „Eigene Dateien“ mit dem Dateinamen kombiniert, und das benötigte Verzeichnistrennzeichen der zugrunde liegenden Plattform wird eingefügt (bei Windows „\“ und bei Mac „/“). Mit File.WriteAllText wird die Datei erstellt (oder ggf. überschrieben), und der Text „Hello World!“ wird in die Datei geschrieben.

Bessere Leistung und mehr Funktionen

Wie Sie sehen können, umfasst die neue CLR in Silverlight 4 Verbesserungen bei Laufzeit und Basisklassen. Das neue GC-Verhalten, die Tatsache, dass nun NGen für Silverlight Framework-Assemblys verwendet wird, sowie die Leistungsverbesserungen für den isolierten Speicher sorgen dafür, dass Ihre Anwendungen mit Silverlight 4 schneller starten und besser ausgeführt werden. Erweiterungen der Basisklassenbibliothek ermöglichen es Ihnen, mit weniger Code mehr zu erreichen. Die neuen Funktionen (z. B. die Möglichkeit, dass vertrauenswürdige Anwendungen auf das Dateisystem zugreifen können) bieten Ihnen überzeugende neue Anwendungsszenarios.

Andrew Pardoe ist als Programmmanager für CLR bei Microsoft tätig. Er arbeitet an verschiedenen Aspekten des Ausführungsmoduls für sowohl Desktop- als auch Silverlight-Laufzeiten. Sie erreichen ihn unter andrew.pardoe@microsoft.com.

Justin Van Patten ist als Programmmanager im CLR-Team bei Microsoft tätig und arbeitet im Bereich Basisklassenbibliotheken. Sie erreichen ihn über den Blog des BCL-Teams unter https://blogs.msdn.com/b/bclteam/.

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Surupa Biswas, Vance Morrison und Maoni Stephens