.Net Framework und C# SS Dr. Ute Blechschmidt-Trapp

Größe: px
Ab Seite anzeigen:

Download ".Net Framework und C# SS 2010. Dr. Ute Blechschmidt-Trapp"

Transkript

1 .Net Framework und C# SS 2010 Dr. Ute Blechschmidt-Trapp Darmstadt, 20. März 2010

2 Inhaltsverzeichnis 1 Einleitung Motivation Literatur Aufbau Schnellstart Framework Windows Forms 7 3 C# für Entwicklerinnen Syntax Operatoren Partial Strings Performance Typen Strukturen Generika Listen Enumerationen Sprachbesonderheiten Log/Trace Ausnahmen Indexer Iteratoren Delegaten Mulitcastdelegaten Schnittstelle vs. Delegate Ereignisse Attribute und Reektion Attribute Reektion Zugri auf Attribute mit Reektion Lambda-Ausdrücke IDisposable using Serialisierung XML-Dokumentationskommentare Namenskonventionen Aufgaben Komponenten Eigene GUI Steuerelemente Managed Extensibility Framework (MEF) Managed Add-in Framework (MAF) Laden eines Add-Ins Modell Windows Presentation Foundation Architektur Ereignisse WinForm und WPF Datenbankanbindung NET Framework-Datenanbieter

3 Inhaltsverzeichnis DataSet DataSet oder DataReader Entity Framework Mapping von Objekten zu Daten Zugreifen auf und Ändern von Entitätsdaten Datenmodellierung im Entity Framework LINQ Datenbindung Datenbindung in WinForm Datenbindung in WPF Datenbindung in Asp.Net Aufgaben Webentwicklung Asp.Net Masterseiten Lebenszyklus einer Seite Ereignismodell für ASP.NET-Webserversteuerelemente Zustandsverwaltung Konguration Ajax Asp.Net MVC Windows Communication Foundation Problembeispiel Architektur Dienstlaufzeit Messaging Hosting und Aktivierung Windows Workow Foundation Statuscomputerworkows Sequenzielle Workows Net Framework Vokabeln Assembly Anwendungsdomäne (AppDomain) Basisklassen Typsystem von C# c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

4 1 Einleitung 1.1 Motivation Warum biete ich dieses Wahlfach an? Ich habe 10 Jahre bei einem zertizierten Partner von Microsoft gearbeitet und dabei die Microsoft Entwicklungsumgebungen und Möglichkeiten kennen und auch zu schätzen gelernt. Neben Java ist C# die Programmiersprache, die in Stellenanzeigen und Artikeln am Häugsten genannt wird. Auf Client-Maschinen ist Windows immer noch das meist verbreitete Betriebssystem (93stellt Microsoft immerhin 24% der Server - Apache 54%. Sicher, Java und plattformunabhängige Technologien sind primär zu erlernen. Der Markt wünscht aber auch Entwicklerinnen, die sich im Microsoftumfeld auskennen. Dies zeigt eine Statistik des Freelancerportals Gulp 1 oder auch ein Artikel bei heise 2. Die verschiedenen aktuellen Technologien von Microsoft sind mächtig und spannend und es macht Spaÿ, mit einer komfortablen IDE zu arbeiten. Wer sich mit seiner geplanten Anwendung im Microsoftumfeld bewegt, sollte die Möglichkeiten von.net nicht verzichten. Selbst, wer plattformübergreifend denkt und arbeitet, kann von.net protieren, denn es gibt zunehmend mehr Projekte, in denen Java und C# zusammen eingesetzt werden. Leider oder zum Glück gibt es im.net Umfeld ca. alle 2 Jahre eine neue Version. Glück für die Entwicklerinnen, die stumpfsinniges Arbeiten durch mächtige Werkzeuge und Bibliotheken weiter abgenommen bekommen und leider, da sich die Prinzipien dadurch auch grundlegend ändern können. Was ist also das bleibende Wissen, das in einer Hochschulveranstaltung vermittelt werden soll? Für Entwicklerinnen, die bereits eine OO-Sprache beherrschen, kann dies nicht das Erlernen der Sprache C# sein. Das Erlernen einer weiteren OO-Sprache ist keine Herausforderung. C# und Java sind sehr ähnlich. In dieser Veranstaltung werden wir uns also auf die Unterschiede konzentrieren. Der Fokus dieser Vorlesung liegt auf dem Arbeiten mit.net, wo bekomme ich Hilfe, was sind momentan die empfohlenen Vorgehensweisen und wesentlichen Technologien? Dies ist also kein Anfängerprogrammierkurs für C#, sondern ich versuche, Hochsprachkonzepte am Beispiel von C# darzustellen, z.b. was ist Delegation? Sie erarbeiten durch geeignete Aufgaben die konzeptuellen Unterschiede zu Java. Jedes Kapitel enthält eine Fülle von Links, die weiterführende Informationen enthalten. Das Skript ist eine Sammlung vieler Quellen, vorwiegend aus Microsofts Feder die Ernder können am Besten ausdrücken, was sie womit meinen und wollen. Marketing-Sprüche habe ich weitestgehend entfernt.. Zeitreise: 1980 startete Microsoft mit 40 Mitarbeitern. In den 80ern und 90ern verfolgte das Unternehmen eine abschottende Politik, d.h. Betriebssystem und Anwendungen waren gegenüber Erweiterungen und Austausch von Anwendungsdaten auf Microsoft-Produkte beschränkt. In dieser Zeit entwickelte sich insbesondere in den Hochschulen und einer aktiven Entwicklergemeinde ein relativ schlechtes Image von Microsoft. Das Unternehmen hat seine Strategie geändert, Quellcodes werden veröentlicht, Microsoft arbeitet in vielen Gremien an Standards mit, das.net Framework kann von beliebigen Sprachen genutzt werden, sofern ein entsprechender Vorcompiler existiert und auch der Datenaustausch zwischen Oceanwendungen und Drittanbietern ist Dank XML möglich. 1.2 Literatur Es gibt viele dicke Bücher zu C#, Asp.Net und anderen Themen dieser Vorlesung. Es gibt meiner Meinung nach wenige gute Bücher, die für Quereinsteiger von anderen OO-Sprachen geschrieben werden, so dass Sie viel Geld für Gedrucktes, dass Sie aus anderen Veranstaltungen kennen, ausgeben. Dies, die Schnelllebigkeit von Microsoft-Technologien und die guten Online-Materialien führen zu folgender Linkliste: Microsoft MSDN Das Microsoft Developer Network 1 Marktstudie: Begehrte Programmiersprachen 2 Experten langfristig gefragt 4

5 1.3 Aufbau Channel9 Videos und anderes Lernmatieral patterns & practices: Microsoft Application Architecture Guide, 2nd Edition library/dd aspx Magazin Visual Studio 2010 and.net Framework 4 Training Kit details.aspx?familyid=752cb b-4732-a383-ed5740f02e93&displaylang=en Developer Blogs Andere Code Das war das.net-jahr ein Rückblick Das-war-das-NET-Jahr-2009-ein-Rueckblick html Visual Studio Magazine BlogBook Vorlesung in die Tiefen von.net (mit anonymous anmelden) Codeproject Codeplex Design Patterns Aufbau Ein Kurzeinblick in die Arbeitsweise des Frameworks im folgenden Abschnitt gibt Ihnen den nötigen Hintergrund und die Basis zum Verständnis der folgenden Kapitel. Mit WinForm wurden früher Client-GUI-Applikationen entwickelt. Diese Technologie wird zunehmend von Windows Presentation Foundation abgelöst. Dennoch starten wir in Kapitel 2 mit WinForm, so dass die weiteren Applikationen im Praktikum nicht nur auf der Console laufen müssen. In Kapitel 3 lernen Sie die grundlegende Syntax und die Besonderheiten von C# kennen. Das Framework zeichnet sich durch das Zusammenspiel von verschiedenen Komponenten aus. Wie Sie selbst komponentenbasierte und durch Komponenten zur Laufzeit erweiterbare Applikationen entwickeln können, erfahren Sie in Kapitel 4. Die Basis ansprechender Benutzeroberächen in.net bildet Windows Presentation Foundation. In diese Technologie führt Kapitel 5 ein. Kapitel 6 beschäftigt sich mit allen Fragen der Anbindung an Datenbanken. Die Grundlagen der Webentwicklung stellt Kapitel 7 vor. In Kapitel 8 erhalten Sie eine kurze Einführung in Windows Communication Foundation und in Kapitel 9 eine kurze Einführung in Windows Work- ow Foundation. Abschlieÿend schauen wir uns das.net Framework in Kapitel 10 noch einmal genauer an wobei ich aufgrund des Umfangs der Vorlesung Sicherheitsfragen leider nicht genauer betrachten kann. Dies ist eine Alpha-Version des Skripts. Informieren Sie mich bitte über Fehler, Unklarheiten, Lücken, machen Sie Vorschläge für eine bessere Struktur, verständlichere Formulierungen, Übungsaufgaben, Schaubilder. Ich freue mich über jede konstruktive Kritik. Obwohl ich viele Jahre im Microsoftumfeld entwickelt habe, sind mir einige der hier vorgestellten Technologien auch nur aus der Theorie oder in älterer Version bekannt. In der Produktentwicklung hat man immer auch mit Altlasten zu kämpfen, Kundenserver werden nicht leichtfertig auf neue Versionen umgestellt, so dass aktuelle Technologien nur bedingt zeitnah in den Entwicklungsabteilungen ankommen. Wenn Sie Erfahrungen mit.net haben, bringen Sie diese bitte ein! 5 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

6 1.4 Schnellstart Framework Abbildung 1.1: Ausführungsmodell 1.4 Schnellstart Framework In Abschnitt 10 auf Seite 73 schauen wir uns das.net Framework genauer an. Für das Verständnis einiger Eigenschaften von C# und die ersten Aufgaben im Praktikum, ist jedoch ein grobes Verständnis hilfreich..net Framework hat ähnlich wie Java eine Laufzeitumgebung, die vorcompilierten Code ausführt. Mit einem Vorcompiler wird Programmcode in die Common Intermediate Language (CIL) (teilweise auch nur Intermediate Language (IL) genannt) übersetzt. CIL ist eine objektorientierte Assemblersprache. Das physikalische Ergebnis dieses Compilevorgangs sind die sogenannten Assemblies (siehe Abschnitt 10.2 auf Seite 78). Der Just in time compiler (JIT) erzeugt daraus sogenannten Managed Code, der in der Common Language Runtime (CLR) für das jeweilige Betriebssystem umgesetzt wird. Managed Code ist per Denition Code, der von der CLR interpretiert wird. Jeder andere Code ist unmanaged. Abbildung 1.2: Common Type System In.Net sind alle Sprachen gleichwertig. Ein einheitliches Typsystem ermöglicht das direkte Zusammenspiel einzelner Assemblies, die in unterschiedlichen Sprachen implementiert sein können. Dabei ist zu beachten, dass alles ein Objekt ist. Werttypen landen auf dem Stack und alle anderen Typen auf dem Heap, der vom Garbage Collector der CLR gegebenenfalls aufgeräumt wird. Entwickler müssen sich im Allgemeinen nicht um die Speicherverwaltung kümmern, sollten aber im Hinterkopf behalten, dass alles auf dem Heap mit Adressen zu tun hat. 6 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

7 2 Windows Forms Abbildung 2.1: Windowsentwicklung Microsoft startete mit einem erfolgreichen Betriebssystem und Software (Oce) für Client-Rechner. Daher haben sich Entwicklerinnen, die für Microsoft-Betriebssysteme entwickelt haben, auf Client-Entwicklung fokusiert. Hierin liegt der Ursprung und die Stärke von VB6, schnell Produkte oder Ergänzungen (damals als ActiveX) zur Oce-Palette zu entwickeln, die Aufgaben von Anwendern automatisieren oder unterstützen. 1 Windows Forms (WinForm) war lange Zeit die Basis zur Erstellung von fensterbasierten Windows-Desktop- Anwendungen. War, denn mit Windows Presentation Foundation (WPF) ist Microsoft den nächsten Schritt gegangen. Das Ergebnis sehen Sie auch in der IDE VS2010, die komplett auf WPF basiert. Mehr dazu in Abschnitt 5 auf Seite 45. Dennoch möchte ich mit WinForm beginnen. WinForm ist eine ereignisbasierte Technologie für Fensteroberächen, wie viele andere GUI-Technologien auch. Die Erstellung der Oberäche gestaltet sich sehr einfach, mit dem Designer im VS die entsprechenden Elemente auf die Oberäche ziehen, possitionieren, Eigenschaften setzen und implementieren, wie auf welche Eigenschaften reagiert werden soll. Es gibt also immer eine Design-Ansicht und eine Implementationssicht - die Designansicht lässt sich auch im Programmcode ansehen und ggf. verändern. WinForms sind prinzipiell pixelbasierte, absolut possitionierte Fenster. Windows Forms enthält eine Vielzahl von Steuerelementen, die Sie Formularen hinzufügen können: Steuerelemente zur Anzeige von Textfeldern, Schaltächen, Dropdownfeldern, Optionsfeldern und sogar Webseiten. Wenn ein vorhandenes Steuerelement Ihre Anforderungen nicht erfüllt, unterstützen Windows Forms auch die Erstellung eigener benutzerdenierter Steuerelemente mithilfe der UserControl-Klasse. Ein Doppelklick im Forms-Designer bewirkt, dass das Visual Studio eine Methode für das Standardereignis der angeklickten Komponente erstellt. Um abweichend vom Standardereignis ein anderes zu behandeln, können Sie das Eigenschaftsfenster einsetzen, nachdem Sie in der Symbolleiste auf die Ereignisliste umgeschaltet haben. Wenn Sie auf ein Ereignis in der Ereignisliste, das Sie behandeln wollen, doppelklicken, wird automatisch ein Ereignishandler erstellt, dessen Bezeichner sich aus dem Objektnamen und dem Ereignis zusammensetzt. Die Bindung des Ereignishandlers nden Sie in InitializeComponent. Sie können dem Ereignishandler auch eine Bezeichnung geben, die von der üblichen Vorgabe abweicht. Dazu tragen Sie nur den von Ihnen bevorzugten Methodennamen in der Wertespalte neben dem Ereignis manuell ein. Möchten Sie einen Ereignishandler gleichzeitig für mehrere Ereignisse registrieren, ist das auch sehr einfach zu lösen. Aktivieren Sie die Wertespalte zu einem Ereignis in der Ereignisliste, sehen Sie eine Schaltäche mit einem Pfeilsymbol. Sie können darüber eine Liste önen, in der alle Ereignishandler aufgeführt sind, die im 1 Übersicht über Windows Forms 7

8 2 Windows Forms Args-Parameter denselben Typ haben. Wählen Sie daraus den Ereignishandler aus, der das markierte Ereignis verarbeiten soll. Wenn Sie Fenster innerhalb anderer Fenster anordnen möchten, dann setzten sie die Eigenschaft IsMdiContainer auf wahr. Aufgabe 2.1 Analysieren Sie die vorhandenen Steuerelemente und beschreiben Sie in einem Satz, wofür welches Steuerelement verwendet wird. 8 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

9 3 C# für Entwicklerinnen Die folgenden Beispiele zeigen die Syntax von C# exemplarisch. In den Unterabschnitten werden Besonderheiten der Sprache dargestellt. Der dazugehörige Text und die Beispiele stammen vorwiegend aus dem C#- Programmierhandbuch von Microsoft. Die Besonderheiten von C# im Vergleich zu Java listet Microsoft selbst auf: C# für Java-Entwickler 3.1 Syntax //Klasse Konstruktoren using System; / Blockkommentar / abstract class Shape public const double pi = Math.PI; protected double x, y, z; Listing 3.1: C# Grundlagen public Shape (double x, double y, double z) this.x = x; this.y = y; this.z = z; public abstract double Area(); class Circle: Shape public Circle(): this(100) //default radius is 100 public Circle(double radius): base(radius,0,0) public override double Area() return pi*x*x; class Cylinder: Circle public Cylinder(double radius, double height): base(radius) y = height; public override double Area() return 2*(base.Area()) + 2*pi*x*y; class TestClass public static void Main() double radius = 2.5, height = 3.0; Circle mycircle = new Circle(radius); Cylinder mycylinder = new Cylinder(radius, height); Console.WriteLine("Area of the circle = 0:F2", mycircle.area()); 9

10 3.1 Syntax Console.WriteLine("Area of the cylinder = 0:F2", mycylinder.area()); // versiegelte Klassen = nal in Java public sealed class D // Class members here. //statische Klassen public static class TemperatureConverter public static double CelsiusToFahrenheit(string temperaturecelsius)... double F, C = 0; F = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine()); // Schnittstellen interface IEquatable<T> bool Equals(T obj); public class Car : IEquatable<Car> //weitere implementierte Interfaces durch, abtrennen private string make; private string model; public string Make get return make; set make = value; public string Model get return model; set model = value; // Implementation of IEquatable<T> interface public bool Equals(Car car) if (this.make == car.make && this.model == car.model) return true; else return false; //If Statement if (condition) / code / else if (othercondition) / code / else / code / //switch geht auch mit String int cost = 0; switch(n) case 1: cost += 25; 10 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

11 3.1 Syntax break; case 2: cost += 25; goto case 1; case 3: cost += 50; goto case 1; default: Console.WriteLine("Invalid selection. Please select 1, 2, or 3."); break; //For Schleife int[] myarray; for (int i = 0; myarray.length; i++) Console.WriteLine(myArray[i]); //Foreach Schleife int[] myarray; foreach (int element in myarray) Console.WriteLine(element); //Using Statement using (StreamWriter sw = new StreamWriter(@"C:\MyFile.txt") sw.write("hello, File"); //Arrays // Declare a single dimensional array int[] array1 = new int[5]; // Declare and set array element values int[] array2 = new int[] 1, 3, 5, 7, 9 ; // Alternative syntax int[] array3 = 1, 2, 3, 4, 5, 6 ; // Declare a two dimensional array int[,] multidimensionalarray1 = new int[2, 3]; // Declare and set array element values int[,] multidimensionalarray2 = 1, 2, 3, 4, 5, 6 ; // Declare a jagged array int[][] jaggedarray = new int[6][]; // Set the values of the rst array in the jagged array structure jaggedarray[0] = new int[4] 1, 2, 3, 4 ; Gleichheit von Objekten: Zwei Objekte sind gleich, wenn deren Inhalte gleich sind Zwei Objekte sind identisch, wenn sie die gleiche Instanz referenzieren Gleichheit deniert sich über die virtuelle Methode System.Object.Equals identisch: System.Object.Equals = true gleich: System.Object.Equals.Value = true. Ähnlich wie in anderen OO-Sprachen gibt es die Zugrismodizierer private, public und protected. C# unterstützt auch internal. 1 public Auf den Typ oder Member kann von jedem Code in der gleichen Assembly siehe Abschnitt 10.2 auf Seite 78 oder einer anderen Assembly, die darauf verweist, zugegrien werden. private Auf den Typ oder Member kann nur von Code in der gleichen Klasse oder Struktur zugegrien werden. protected Auf den Typ oder Member kann nur von Code in der gleichen Klasse oder Struktur oder in einer abgeleiteten Klasse zugegrien werden. 1 Zugrismodizierer 11 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

12 3.1 Syntax internal Auf den Typ oder Member kann von jedem Code in der gleichen Assembly zugegrien werden, jedoch nicht von Code in einer anderen Assembly. protected internal Auf den Typ oder Member kann von jedem Code in der gleichen Assembly oder von jeder abgeleiteten Klasse in einer anderen Assembly zugegrien werden. Methoden und Konstruktoren können überladen werden, ebenso können die meisten Operatoren überladen werden: Arithmetische, Vergleichs-, Logik- und Bedingungsoperatoren. Ausnahmen sind Zuweisungsoperatoren, Spezialoperatoren wie sizeof, new, is und typeof Operatoren In Bezug auf Operatoren möchte ich auch noch auf den tertiären Operator? mit : hinweisen, den es auch in anderen Programmiersprachen wie z.b. PHP gibt, der jedoch seltener als wünschenswert eingesetzt wird. Ähnlich dazu, gibt es den?? Operator. Dieser ist äuÿerst hilfreich, wenn Objekte auf null hin überprüft werden sollen. Es wird die Linke Seite evaluiert. Ist diese nicht null, wird der linke Wert zurückgegeben, andernfalls der rechte. Listing 3.2: Operatoren //Variante mit Bedingung?Wahrfall:Falschfall; string r = ( v == null )? "null" : v; //Variante mit dem?? Operator: string r = v?? "null"; //+ einmal anders class Matrix... Matrix operator +(Matrix l, Matrix r) Matrix e = new Matrix(); e = l mit r verknüpfen return e;... Matrix a = new Matrix(...), b = new Matrix(...); Matrix c = a + b; Partial Die Denitionen partieller Typen ermöglichen es, die Denition einer Klasse, einer Struktur oder einer Schnittstelle auf mehrere Dateien aufzuteilen. Einen Klassen-, Struktur- oder Schnittstellentyp auf mehrere Dateien aufzuteilen kann hilfreich sein, wenn Sie mit groÿen Projekten oder mit automatisch generiertem Code wie z.b. von Der Windows Forms-Designer bereitgestellt. Verwenden Sie hierfür das Schlüsselwort partial, also z.b. partial class A in zwei Dateien Strings Eine Zeichenfolge ist ein Objekt vom Typ String, dessen Wert Text ist. Intern wird der Text als schreibgeschützte Auistung von Char-Objekten gespeichert, von denen jedes ein in UTF-16 codiertes Unicode-Zeichen darstellt. Eine C#-Zeichenfolge wird nicht mit einem NULL-Zeichen am Ende terminiert (im Gegensatz zu C und C++). Deshalb kann eine C#-Zeichenfolge eine beliebige Anzahl eingebetteter NULL-Zeichen (' 0') enthalten. Die Länge einer Zeichenfolge stellt die Anzahl der Zeichen unabhängig davon dar, ob die Zeichen aus Unicode-Ersatzzeichenpaaren gebildet werden oder nicht. Um in einer Zeichenfolge auf die einzelnen Unicode-Codepunkte zuzugreifen, verwenden Sie das StringInfo-Objekt. In C# ist das string-schlüsselwort ein Alias für String. Deshalb entsprechen sich String und string, und Sie können eine beliebige Namenskonvention verwenden. Die String-Klasse stellt viele Methoden zum sicheren Erstellen, Bearbeiten und Vergleichen von Zeichenfolgen bereit. Initialisieren Sie eine Zeichenfolge mit dem konstanten Empty-Wert, um ein neues String-Objekt zu erstellen, dessen Zeichenfolge die Länge NULL aufweist. Durch die Initialisierung von Zeichenfolgen mit dem Wert Empty 12 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

13 3.2 Performance anstelle von null können Sie die Chancen einer NullReferenceException reduzieren. Verwenden Sie die statische IsNullOrEmpty(String)-Methode, um den Wert einer Zeichenfolge zu prüfen, bevor Sie versuchen, darauf zuzugreifen. Da eine Zeichenfolgenänderung einer neuen Zeichenfolgenerstellung gleichkommt, müssen Sie beim Erstellen von Verweisen auf Zeichenfolgen vorsichtig sein. Wenn Sie einen Verweis auf eine Zeichenfolge erstellen und dann die ursprüngliche Zeichenfolge ändern, zeigt der Verweis weiterhin auf das ursprüngliche Objekt und nicht auf das neue Objekt, das beim Ändern der Zeichenfolge erstellt wurde. Der folgende Code veranschaulicht dieses Verhalten: string s1 = "Hello "; string s2 = s1; s1 += "World"; System.Console.WriteLine(s2); //Output: Hello Listing 3.3: Stringreferenz string s1 = "Hello "; string s2 = s1; s1 = "Hello World"; System.Console.WriteLine(s2); Listing 3.4: Stringreferenz Aufgabe 3.1 Was wird in Listing 3.4 ausgegeben? Längere Strings oder Pfade können Sie in C# mit einem denieren. string path string quote name was ""Sara."""; string minitemplate 0, Your friend 1 sent you this message: 2 That's all!"; Listing 3.5: Strings - ähnlich Heredoc von PHP string populatedtemplate = String.Format(miniTemplate, "Fred", "Jack", "HelloWorld!"); System.Console.WriteLine(populatedTemplate); 3.2 Performance Zeichenfolgenobjekte sind unveränderlich. Das bedeutet, dass sie nicht mehr geändert werden können, nachdem sie erstellt wurden. Alle String-Methoden und C#-Operatoren, mit denen eine Zeichenfolge geändert werden könnte, geben diese Ergebnisse in einem neuen Zeichenfolgenobjekt zurück. Im folgenden Beispiel bleiben beim Verketten des Inhalts von s1 und s2 zu einer einzelnen Zeichenfolge die beiden ursprünglichen Zeichenfolgen unverändert. Der Operator += erstellt eine neue Zeichenfolge, die die kombinierten Inhalte enthält. Dieses neue Objekt wird der Variablen s1 zugewiesen. Das ursprüngliche Objekt, das s1 zugewiesen wurde, wird für die Garbage Collection freigegeben, da keine andere Variable einen Verweis darauf enthält. Mit der Klasse StringBuilder können Sie ohne das Zerstören und Neuerstellen von Objekten speicherezient Zeichenketten zusammenführen. Die Klasse enthält auch weitere nützliche Methoden. int x = 4; StringBuilder sb = new StringBuilder(); sb.append(x.tostring()); sb.appendformat("ghi01", 'J', 'k'); Listing 3.6: StringBuilder zur Verkettung von Strings 13 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

14 3.3 Typen sb.append(" und "); //Einen Text am Anfang einfügen sb.insert(0, "Alphabet: "); sb.replace('k', 'K'); Console.WriteLine("0 chars: 1", sb.length, sb.tostring()); Noch eine Performanceverbesserung gibt es beim Prüfen auf Leerstrings: Der Vergleich von Zeichenfolgen mit der System.String.Length-Eigenschaft oder der System.String.IsNullOrEmpty(System.String)-Methode ist bedeutend schneller als ein Vergleich mit Equals. string s1 = "test"; //nicht performant if (s1 == "") if (!String.IsNullOrEmpty(s1) ) Console.WriteLine("s1!= null and s1.length!= 0."); Listing 3.7: String auf leer prüfen Neben StringBuilder und dem Prüfen auf Leerstrings gibt es weitere Möglichkeiten, Code performanter zu schreiben. Wenn Sie ein Feld als static und readonly deklarieren und mit einem Wert initialisieren, dann sollten Sie stattdessen const verwenden. Der Wert eines const-felds wird zur Kompilierungszeit berechnet und in den Metadaten gespeichert. Dadurch wird im Vergleich zu einem static readonly-feld die Laufzeitleistung gesteigert. Wenn mit dem is-operator von C# getestet wird, ob die Umwandlung erfolgreich durchgeführt werden kann, bevor die eigentliche Umwandlung erfolgt, sollten Sie erwägen, stattdessen das Ergebnis des as-operators zu testen. Dieses Vorgehen bietet die gleiche Funktionalität ohne die implizite vom is-operator ausgeführte Umwandlungsoperation. // The 'is ' statement performs a cast operation. if(obj is Control) // The 'as' statement performs a duplicate cast operation. Control acontrol = obj as Control; // Use acontrol. //besser: Control acontrol = obj as Control; if(acontrol!= null) // Use acontrol. Listing 3.8: is/as performant einsetzen Zur Analyse Ihres Codes, können Sie eine hilfreiche Eigentschaft Ihres Projekts setzen: Option Codeanalyse aktivieren. Weitere Empfehlungen zur Erstellung von hochwertigem Code nden Sie unter Verfassen von qualitativ hochwertigem Quellcode und darin insbesondere Leistungswarnungen. 3.3 Typen Strukturen Klassen und Strukturen sind zwei der grundlegenden Konstrukte des allgemeinen Typsystems in.net Framework. Bei beiden handelt es sich um eine Datenstruktur, die einen als logische Einheit zusammengehörenden Satz von Daten und Verhalten kapselt. Die Daten und Verhalten sind die Member der Klasse oder Struktur. Diese enthalten deren Methoden, Eigenschaften, Ereignisse usw. Eine Struktur ist ein Werttyp (siehe Abschnitt 10.5 auf Seite 1). Wenn eine Struktur erstellt wird, enthält die Variable, der die Struktur zugewiesen wird, die eigentlichen Daten der Struktur. Wenn die Struktur einer neuen Variable zugewiesen wird, werden diese kopiert. Die neue Variable und die ursprüngliche Variable enthalten daher zwei separate Kopien der gleichen Daten. Änderungen an einer Kopie wirken sich nicht auf die andere Kopie aus. Im Allgemeinen werden Klassen zum Modellieren von komplexerem Verhalten oder von Daten verwendet, die dafür vorgesehen sind, nach der Erstellung eines Klassenobjekts geändert zu werden. Strukturen sind am besten für kleine Datenstrukturen geeignet, die überwiegend Daten enthalten, deren Änderung nach der Erstellung der Struktur nicht vorgesehen ist. 14 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

15 3.3 Typen Besonderheiten von Strukturen im Vergleich zu Klassen: Strukturen haben fast die gleiche Syntax wie Klassen, unterliegen jedoch mehr Beschränkungen als Klassen: Innerhalb einer Strukturdeklaration können Felder nur dann initialisiert werden, wenn sie als konstant oder statisch deklariert werden. Eine Struktur kann keinen Standardkonstruktor (ein Konstruktor ohne Parameter) und keinen Destruktor deklarieren. Strukturen können nicht von Klassen oder anderen Strukturen erben. Strukturen werden durch Zuweisung kopiert. Wenn eine Struktur einer neuen Variablen zugewiesen wird, werden alle Daten kopiert. Änderungen an der neuen Kopie wirken sich nicht auf die Daten in der ursprünglichen Kopie aus. Strukturen sind Werttypen, und Klassen sind Referenztypen. Strukturen können im Gegensatz zu Klassen ohne einen Operator new instanziiert werden. Strukturen können Konstruktoren deklarieren, die über Parameter verfügen. Eine Struktur ist nicht in der Lage, von einer anderen Struktur oder Klasse zu erben, und sie kann auch nicht die Basis einer Klasse sein. Alle Strukturen erben direkt von System.ValueType, welcher von System.Object erbt. Eine Struktur kann Schnittstellen implementieren. Lapidar gesagt, Strukturen sind gut für die Darstellung zusammengehörender Daten, für die Modellierung von Verhalten und wenn Vererbung benötigt wird, sollten Klassen verwendet werden. Listing 3.9: Beispiel für Strukturen public struct CoOrds public int x, y; public CoOrds(int p1, int p2) x = p1; y = p2; struct/objekt Parameterübergabe: Da Strukturen Werttypen sind und Objekte Referenztypen sind, gilt: Wenn struct an eine Methode übergeben wird, wird eine Kopie der Struktur übergeben. Bei der Übergabe einer class-instanz wird jedoch ein Verweis übergeben Generika Manchmal möchte man eine Klasse oder Parameter einer Methode so allgemein halten, dass sie mit Objekten verschiedener Typen arbeiten können. Dies könnte man durch den allgemeinsten Datentyp Object erreichen, damit können Typen jedoch gemischt werden. Möchte man auf Typsicherheit nicht verzichten, so kann man Generika einsetzen. Häug verwendet man generische Listen, um z.b. Stringlisten, Int-Listen oder Listen von Objekten einer Klasse zu verarbeiten. public class GenericList<T> void Add(T input) class TestGenericList private class ExampleClass static void Main() Listing 3.10: Generika 15 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

16 3.3 Typen GenericList<int> list1 = new GenericList<int>(); GenericList<string> list2 = new GenericList<string>(); GenericList<ExampleClass> list3 = new GenericList<ExampleClass>(); Listen Abbildung 3.1: Listen.NET Framework stellt spezialisierte Klassen für das Speichern und Abrufen von Daten bereit. Diese Klassen bieten Unterstützung für Stapel, Warteschlangen, Listen und Hashtabellen. Die meisten Auistungsklassen implementieren dieselben Schnittstellen. Diese Schnittstellen können geerbt werden, um neue, auf speziellere Datenspeicherungsanforderungen zugeschnittene Auistungsklassen zu erstellen. Hashtable stellt eine Auistung von Schlüssel-Wert-Paaren dar, die nach dem Hashcode des Schlüssels organisiert sind. Die generische Dictionary<(Of <(TKey, TValue>)>)-Klasse stellt eine Zuordnung von einem Satz von Schlüsseln zu einem Satz von Werten bereit. Jede Hinzufügung zum Wörterbuch besteht aus einem Wert und dem zugeordneten Schlüssel. Ein Wert kann anhand des zugehörigen Schlüssels sehr schnell abgerufen werden (beinahe ein O(1)-Vorgang), da die Dictionary<(Of <(TKey, TValue>)>)-Klasse in Form einer Hashtabelle implementiert ist. Wenn ein Objekt im Dictionary<(Of <(TKey, TValue>)>) als Schlüssel verwendet wird, darf es nicht auf eine Weise geändert werden, die sich auf seinen Hashwert auswirkt. Jeder Schlüssel in einem Dictionary<(Of <(TKey, TValue>)>) muss für den Gleichheitsvergleich des Wörterbuches eindeutig sein. ArrayList implementiert die IList-Schnittstelle unter Verwendung eines Arrays, das nach Bedarf dynamisch vergröÿert wird. Es wird nicht sichergestellt, dass die ArrayList sortiert ist. Sie müssen die ArrayList sortieren, bevor Sie Vorgänge wie BinarySearch durchführen, die eine sortierte ArrayList voraussetzen. Die List<(Of <(T>)>)-Klasse stellt die generische Entsprechung der ArrayList-Klasse dar. Sie implementiert die generische IList<(Of <(T>)>)-Schnittstelle unter Verwendung eines Arrays, das nach Bedarf dynamisch vergröÿert wird. Queue stellt eine FIFO-Auistung (First-In-First-Out) von Objekten dar. Stack stellt eine LIFO (Last-In-First-Out)-Auistung variabler Gröÿe von Instanzen desselben beliebigen Typs dar. Hashtable openwith = new Hashtable(); openwith.add("txt", "notepad.exe"); Listing 3.11: Listen Dictionary<string, string> openwith2 = new Dictionary<string, string>(); 16 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

17 3.3 Typen openwith2.add("txt", "notepad.exe"); ArrayList myal = new ArrayList(); myal.add("hello"); List<string> dinosaurs = new List<string>(); dinosaurs.add("tyrannosaurus"); Queue<string> numbers = new Queue<string>(); numbers.enqueue("one"); Stack<string> numbers = new Stack<string>(); numbers.push("one"); Wählen Sie Ihre System.Collections-Klasse sorgfältig aus. Wenn der falsche Typ ausgewählt wird, kann dies die Verwendung der Auistung einschränken. Beachten Sie Folgendes: Benötigen Sie eine sequenzielle Liste, bei der ein Element normalerweise verworfen werden kann, wenn sein Wert abgerufen wurde? Benötigen Sie Zugri auf Elemente in einer bestimmten Reihenfolge, z. B. FIFO-, LIFO- oder beliebiger Reihenfolge? Möchten Sie auf die einzelnen Elemente mithilfe eines Indizes zugreifen? ArrayList, List, Hashtable, SortedList, ListDictionary und StringDictionary Wird jedes Element einen Wert enthalten, eine Kombination aus einem Schlüssel und einem Wert oder eine Kombination aus einem Schlüssel und mehreren Werten? Müssen die Elemente unabhängig von der Reihenfolge ihrer Eingabe sortiert werden? Ist schnelles Suchen und Abrufen von Informationen erforderlich? Werden Auistungen gebraucht, die nur Zeichenfolgen annehmen? Enumerationen Ein Enumerationstyp (auch als Enumeration bezeichnet) bietet eine eziente Möglichkeit, einen Satz benannter integraler Konstanten zu denieren, die einer Variablen zugewiesen werden können. Angenommen, Sie müssen eine Variable denieren, deren Wert einen Wochentag darstellt. Es gibt nur sieben sinnvolle Werte, die diese Variable speichern kann. Um diese Werte zu denieren, können Sie einen Enumerationstyp verwenden, der durch die Verwendung des enum-schlüsselworts deklariert wird. Der zugrunde liegende Standardtyp aller Elemente in der Enumeration lautet int. Listing 3.12: Enumerationen enum Days Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday ; enum Months : byte Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec ; Days meetingday = Days.Monday; enum MachineState PowerOff = 0, Running = 5, Sleeping = 10, Hibernating = Sleeping + 5 Sie können einen Enumerationstyp verwenden, um Bitags zu denieren. Dadurch kann eine Instanz des Enumerationstyps eine Kombination aus den Werten speichern, die in der Enumeratorliste deniert sind. Im folgenden Beispiel wird eine andere Version des Days-Enumerators, der als Days2 bezeichnet ist, deniert. Days2 weist das Flags-Attribut auf, und jedem Wert wird die nächste höhere Potenz von 2 zugewiesen. So können Sie eine Days2-Variable erstellen, deren Wert Days2.Tuesday und Days2.Thursday lautet. Um ein Flag eines Enumerators festzulegen, verwenden Sie den logischen OR-Operator. Um zu ermitteln, ob ein bestimmtes Flag festgelegt ist, verwenden Sie eine logische AND-Operation. 17 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

18 3.4 Sprachbesonderheiten [Flags] enum Days2 None = 0x0, Sunday = 0x1, Monday = 0x2, Tuesday = 0x4, Wednesday = 0x8, Thursday = 0x10, Friday = 0x20, Saturday = 0x40 class MyClass Days2 meetingdays = Days2.Tuesday Days2.Thursday; private void pleassure() // Initialize with two ags using bitwise OR. meetingdays = Days2.Tuesday Days2.Thursday; // Set an additional ag using bitwise OR. meetingdays = meetingdays Days2.Friday; Listing 3.13: Enumeration als Flags Console.WriteLine("Meeting days are 0", meetingdays); // Output: Meeting days are Tuesday, Thursday, Friday // Remove a ag using bitwise XOR. meetingdays = meetingdays ^ Days2.Tuesday; Console.WriteLine("Meeting days are 0", meetingdays); // Output: Meeting days are Thursday, Friday // Test value of ags using bitwise AND. bool test = (meetingdays & Days2.Thursday) == Days2.Thursday; Console.WriteLine("Thursday 0 a meeting day.", test == true? "is" : "is not"); // Output: Thursday is a meeting day. 3.4 Sprachbesonderheiten Log/Trace Mit der Trace-Klasse lassen sich Anwendungen instrumentieren. Von einer laufenden Anwendung können Sie damit Informationsmeldungen erhalten, die beim Diagnostizieren von Problemen oder Analysieren der Leistung hilfreich sind. Trace.WriteLine("Entering Main"); Listing 3.14: Trace Mächtiger und besser zu kongurieren ist log4net Ausnahmen 2 Die Features zur Ausnahmebehandlung in C# helfen Ihnen, wenn bei der Ausführung eines Programms unerwartete oder auÿergewöhnliche Situationen auftreten. Bei der Ausnahmebehandlung wird mithilfe der Schlüsselwörter try, catch und nally versucht, Aktionen auszuführen, die möglicherweise fehlschlagen, um Fehler zu behandeln und anschlieÿend die Ressourcen zu bereinigen. Ausnahmen können von der Common Language Runtime (CLR ähnlich zur Virtual Maschine von Java), durch.net Framework oder Bibliotheken von Drittanbietern oder durch den Anwendungscode generiert werden. Ausnahmen werden mit dem throw-schlüsselwort erstellt. Es gibt jedoch im Gegensatz zu Java keine Syntax, die kennzeichnet, welche Klassen welche Ausnahmen werfen können throws wird in C# also nur zum tatsächlichen Erzeugen/werfen von Ausnahmen verwendet. In vielen Fällen wird eine Ausnahme nicht von einer Methode ausgelöst, die direkt durch den Code aufgerufen wurde, sondern von einer anderen Methode, die sich weiter unten in der Aufruiste bendet. In diesem Fall 2 Ausnahmen und Ausnahmebehandlung 18 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

19 3.4 Sprachbesonderheiten Abbildung 3.2: Aunden einer passenden catch-denition entlädt die CLR die Aufruiste, sucht eine Methode mit einem catch-block für den spezischen Ausnahmetyp und führt den ersten catch-block aus, der gefunden wird. Falls kein entsprechender catch-block in der Aufruiste gefunden wird, wird der Prozess beendet und eine Meldung für den Benutzer angezeigt. Ausnahmen sind Typen, die letztlich alle von System.Exception abgeleitet werden. Fangen Sie keine Ausnahme ab, es sei denn, Sie können sie bearbeiten, und belassen Sie die Anwendung in einem bekannten Zustand. Wenn Sie System.Exception abfangen, lösen Sie es erneut mit dem throw-schlüsselwort am Ende des catch-blocks aus. Ausnahmeobjekte enthalten ausführliche Informationen zum Fehler, z. B. den Zustand der Aufruiste und eine Textbeschreibung des Fehlers. Nicht abgefangene Ausnahmen werden von einem generischen Ausnahmehandler des Systems behandelt, der ein Dialogfeld anzeigt. Im Gegensatz zu Java, gibt es keine Checked Exceptions. Eine Abbildung 3.3: CheckedException Java vs C# Checked Exception ist eine Ausnahme, bei der der Compiler prüft, ob alle Stellen, wo sie auftreten kann, durch Code zum Abfangen der Ausnahme abgedeckt sind. Der Code zum Abfangen kann dabei innerhalb derselben Methode stehen, in der die Ausnahme auftreten kann, oder auch in aufrufenden Methoden. Der Compiler wird bei Java durch das Schlüsselwort throws unterstüzt. Bei C# ist dies nicht so umgesetzt. Fängt niemand eine Exception, so bricht das Programm mit dem generischen Fehlerdialog ab. Per Design ist dies vermutlich ein Nachteil. Da jedoch viele Java-Programmierer einfach mit catch (E e) Listing 3.15: Schlechter Code Fehler schlucken Fehler schlucken, führt dies weningstens nicht zu nicht-erklärbaren Verhalten, sondern der Fehler bleibt erhalten. 19 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

20 3.4 Sprachbesonderheiten Indexer 3 einer Klasse oder Struktur auf dieselbe Weise wie Arrays. Abgesehen davon, dass ihre Accessoren Parameter akzeptieren, sind Indexer mit Eigenschaften vergleichbar. Im folgenden Beispiel wird eine generische Klasse deniert, die mit einfachen get-accessormethoden und set- Accessormethoden ausgestattet ist. Mit diesen Methoden werden Werte zugewiesen und abgerufen. Die Program- Klasse erstellt eine Instanz dieser Klasse für das Speichern von Zeichenfolgen. class SampleCollection<T> private T[] arr = new T[100]; public T this[int i] get return arr[i]; set arr[i] = value; Listing 3.16: Indexer // This class shows how client code uses the indexer class Program static void Main(string[] args) SampleCollection<string> stringcollection = new SampleCollection<string>(); stringcollection[0] = "Hello, World"; System.Console.WriteLine(stringCollection[0]); Übersicht über Indexer Durch Indexer können Objekte auf ähnliche Weise wie Arrays indiziert werden. Ein get-accessor gibt einen Wert zurück. Ein set-accessor weist einen Wert zu. Das this-schlüsselwort wird zum Denieren der Indexer verwendet. Mithilfe des value-schlüsselworts wird der Wert deniert, der vom set-indexer zugewiesen wird. Indexer müssen nicht mit ganzzahligen Werten indiziert werden. Sie können frei wählen, wie Sie den bestimmten Suchmechanismus denieren. Indexer können überladen werden. Indexer können mehr als einen formalen Parameter haben, z. B. wenn auf ein zweidimensionales Array zugegrien wird Iteratoren Möchte man eine Klasse mit foreach durchlaufen, so benötigt man die Methode GetEnumerator. Listing 3.17: Iteratoren public class DaysOfTheWeek : System.Collections.IEnumerable string[] days = "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" ; public System.Collections.IEnumerator GetEnumerator() for (int i = 0; i < days.length; i++) 3 Indexer 20 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

21 3.5 Delegaten yield return days[i]; class TestDaysOfTheWeek static void Main() // Create an instance of the collection class DaysOfTheWeek week = new DaysOfTheWeek(); // Iterate with foreach foreach (string day in week) System.Console.Write(day + " "); 3.5 Delegaten Ein Delegate ist ein Objekt, welches auf eine Methode zeigt, die zu einem späteren Zeitpunkt aufgerufen werden kann. Delegaten verfügen über folgende Eigenschaften: Delegaten ähneln C++-Funktionszeigern, sind aber typsicher. Delegaten ermöglichen es, Methoden als Parameter zu übergeben. Delegaten können zum Denieren von Rückrufmethoden verwendet werden. Delegaten können miteinander verkettet werden. So können beispielsweise mehrere Methoden für ein einziges Ereignis aufgerufen werden. Delegate: Delegate folgen dem Design Pattern Publish/Subscribe. Das folgende Listing zeigt, wie ein Delegate deniert wird. public delegate void Del<T>(T item); public void Notify(int i) Del<int> d1 = new Del<int>(Notify); //gleichwertig zu Del<int> d2 = Notify; Listing 3.18: Delegaten Dieses Beispiel zeigt ein Delegate mit Verweis auf eine statische Funktion und mit einer nicht-statischen Funktion Listing 3.19: Delegaten, Beispiel 1 namespace Bookstore 2 3 using System.Collections; 4 public struct Book 5 6 public string Title; // Title of the book. 7 public string Author; // Author of the book. 8 public decimal Price; // Price of the book. 9 public bool Paperback; // Is it paperback? public Book(string title, string author, decimal price, bool paperback) Title = title; 14 Author = author; 15 Price = price; 16 Paperback = paperback; 21 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

22 3.5 Delegaten Abbildung 3.4: Delegaten public delegate void ProcessBookDelegate(Book book); 20 public class BookDB ArrayList list = new ArrayList(); 23 public void AddBook(string title, string author, decimal price, bool paperback) list.add(new Book(title, author, price, paperback)); public void ProcessPaperbackBooks(ProcessBookDelegate processbook) foreach (Book b in list) c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

23 3.5 Delegaten 31 if (b.paperback) 32 // Calling the delegate: 33 processbook(b); namespace BookTestClient using Bookstore; 41 class PriceTotaller int countbooks = 0; 44 decimal pricebooks = 0.0m; internal void AddBookToTotal(Book book) countbooks += 1; 49 pricebooks += book.price; internal decimal AveragePrice() return pricebooks / countbooks; class TestBookDB static void PrintTitle(Book b) System.Console.WriteLine(" 0", b.title); static void Main() BookDB bookdb = new BookDB(); 66 AddBooks(bookDB); 67 System.Console.WriteLine("Paperback Book Titles:"); 68 bookdb.processpaperbackbooks(printtitle); 69 PriceTotaller totaller = new PriceTotaller(); 70 bookdb.processpaperbackbooks(totaller.addbooktototal); 71 System.Console.WriteLine("Average Paperback Book Price: $0:#.##", 72 totaller.averageprice()); static void AddBooks(BookDB bookdb) bookdb.addbook("the C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); 77 bookdb.addbook("the Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); 78 bookdb.addbook("the MS-DOS Encyclopedia", "Ray Duncan", m, false); 79 bookdb.addbook("dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); Aufgabe 3.2 Kommentieren Sie das Programm ausführlich. Beschreiben Sie den Ablauf in Worten oder malen Sie ein geeignetes Bild. Was gibt das Programm aus? Ein Delegat kann entweder (wie in diesem Beispiel) synchron oder mithilfe der BeginInvoke-Methode und der EndInvoke-Methode asynchron aufgerufen werden Mulitcastdelegaten Eine nützliche Eigenschaft von delegate-objekten besteht darin, dass sie mithilfe des Operators + einer Delegatinstanz als Multicast zugewiesen werden können. Ein zusammengesetzter Delegat ruft die beiden Delegaten auf, aus denen er besteht. Es können ausschlieÿlich Delegaten mit demselben Typ kombiniert werden. Mithilfe des Operators - kann ein Komponentendelegat aus einem zusammengesetzten Delegaten entfernt werden. Das folgende Beispiel zeigt die Verwendung dieser Operatoren. Listing 3.20: Multicastdelegaten 23 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

24 3.5 Delegaten delegate void Del(string s); class TestClass static void Hello(string s) System.Console.WriteLine(" Hello, 0!", s); static void Goodbye(string s) System.Console.WriteLine(" Goodbye, 0!", s); static void Main() Del a, b, c, d; a = Hello; b = Goodbye; c = a + b; d = c - a; System.Console.WriteLine("Invoking delegate a:"); a("a"); System.Console.WriteLine("Invoking delegate b:"); b("b"); System.Console.WriteLine("Invoking delegate c:"); c("c"); System.Console.WriteLine("Invoking delegate d:"); d("d"); Aufgabe 3.3 Was gibt das Programm Multicastdelegaten aus? Schnittstelle vs. Delegate 4 Sowohl Delegaten als auch Schnittstellen ermöglichen es einem Klassendesigner, Typdeklarationen und Implementierung voneinander zu trennen. Eine bestimmte Schnittstelle kann von jeder Klasse oder Struktur geerbt und implementiert werden. Ein Delegat kann für eine Methode jeder beliebigen Klasse erstellt werden, solange die Methode mit der Methodensignatur des Delegaten übereinstimmt. Ein Schnittstellenverweis oder ein Delegat kann von jedem Objekt verwendet werden, ohne über Informationen zu der Klasse zu verfügen, die die Schnittstelle oder die Delegatmethode implementiert. Wann sollte ein Klassendesigner in Anbetracht dieser Gemeinsamkeiten einen Delegaten verwenden, und wann sollte eine Schnittstelle verwendet werden? Verwenden Sie Delegaten, wenn ein Ereignisentwurfsmuster verwendet wird. eine statische Methode gekapselt werden soll. der Aufrufer keinen Zugri auf weitere Eigenschaften, Methoden oder Schnittstellen des Objekts benötigt, das die Methode implementiert. die einfache Verknüpfung von Delegaten gewünscht ist. eine Klasse möglicherweise mehr als eine Implementierung der Methode benötigt. Verwenden Sie Schnittstellen, wenn es eine Gruppe verwandter Methoden gibt, die möglicherweise aufgerufen werden. eine Klasse nur eine Implementierung der Methode benötigt. die Klasse, die die Schnittstelle verwendet, eine Umwandlung dieser Schnittstelle in andere Schnittstellen oder Klassentypen durchführt. die Methode, die implementiert wird, mit dem Typ oder der Identität der Klasse verknüpft ist, wie zum Beispiel bei Vergleichsmethoden. 4 Wann sind Delegaten Schnittstellen vorzuziehen? 24 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

25 3.5 Delegaten Ein gutes Beispiel für die Verwendung einer Schnittstelle mit nur einer Methode anstatt eines Delegaten ist IComparable oder die generische Version IComparable<(Of <(T>)>). IComparable deklariert die CompareTo- Methode, die eine ganze Zahl zurückgibt, die ein Kleiner-als-, Gleich- oder Gröÿer-als-Verhältnis zwischen zwei Objekten desselben Typs angibt. IComparable kann als Grundlage für einen Sortieralgorithmus verwendet werden. Die Verwendung einer Delegatenvergleichsmethode als Grundlage für den Sortieralgorithmus ist zwar möglich, aber nicht optimal. Da die Vergleichsfunktionalität zu einer Klasse gehört und der Vergleichsalgorithmus zur Laufzeit nicht geändert wird, stellt eine Schnittstelle mit nur einer Methode die ideale Lösung dar Ereignisse Ereignisse aktivieren eine Klasse oder ein Objekt, um Informationen über Aktionen von Interesse an andere Klassen oder Objekte zu übermitteln. Die Klasse, die das Ereignis sendet (oder auslöst), wird als Herausgeber bezeichnet und die Klassen, die das Ereignis empfangen (oder behandeln), werden als Abonnenten bezeichnet. In einer typischen C# Windows Forms- oder -Webanwendung abonnieren Sie Ereignisse, die von Steuerelementen wie Schaltächen und Listenfeldern ausgelöst wurden. In der integrierten Entwicklungsumgebung (IDE) von Visual C# können Sie die Ereignisse durchsuchen, die ein Steuerelement veröentlicht, und diejenigen auswählen, die Sie behandeln möchten. Die IDE fügt automatisch eine leere Ereignishandlermethode und den Code zum Abonnieren des Ereignisses hinzu. Ereignisse verfügen über folgende Eigenschaften: Der Herausgeber bestimmt, wann ein Ereignis ausgelöst wird; die Abonnenten bestimmen, welche Maÿnahme als Reaktion auf das Ereignis ergrien wird. Ein Ereignis kann mehrere Abonnenten haben. Ein Abonnent kann mehrere Ereignisse von mehreren Herausgebern behandeln. Ereignisse, die keine Abonnenten haben, werden nie ausgeführt. Ereignisse dienen normalerweise zur Signalisierung von Benutzeraktionen wie das Klicken auf Schaltächen oder Auswählen von Menüs in der graschen Benutzeroberäche. Ereignisse können verwendet werden, um Threads zu synchronisieren. In der.net Framework-Klassenbibliothek basieren Ereignisse auf dem EventHandler-Delegaten und der EventArgs-Basisklasse 1 / Denition in System Namensraum 2 public delegate void EventHandler<TEventArgs>( 3 Object sender, 4 TEventArgs e 5 ) 6 / 7 public class MyEventArgs : EventArgs 8 9 privatestring msg; public MyEventArgs( string messagedata ) 12 msg = messagedata; publicstring Message 15 get return msg; 16 set msg = value; public class HasEvent public void DemoEvent(string val) // Copy to a temporary variable to be thread safe. 24 EventHandler<MyEventArgs> temp = SampleEvent; 25 if (temp!= null) 26 temp(this, new MyEventArgs(val)); public class Sample publics tatic void Main() Listing 3.21: Ereignisse 25 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

26 3.5 Delegaten HasEvent he = new HasEvent(); 34 he.sampleevent += 35 new EventHandler<MyEventArgs>(SampleEventHandler); 36 he.demoevent("hey there, Bruce!"); 37 he.demoevent("how are you today?"); private static void SampleEventHandler(object src, MyEventArgs mea) Console.WriteLine(mea.Message); Aufgabe 3.4 Kommentieren Sie das Programm ausführlich. Beschreiben Sie den Ablauf in Worten oder malen Sie ein geeignetes Bild. Was gibt das Programm aus? Aufgabe 3.5 Arbeiten Sie das Zusammenspiel von Delegaten und Events anhand des Artikels im Anhang?? heraus. Aufgabe 3.6 Kommentieren Sie das Programm ausführlich. Beschreiben Sie den Ablauf in Worten oder malen Sie ein geeignetes Bild. Listing 3.22: Asynchrone Delegate 1 using System; 2 using System.Threading; 3 using System.Runtime.Remoting.Messaging; 4 //Quelle: de/library/h80ttd5f%28en us,vs.100%29.aspx 5 namespace Examples.AdvancedProgramming.AsynchronousOperations 6 7 // Create a class that factors a number. 8 public class PrimeFactorFinder 9 10 public static bool Factorize( 11 int number, 12 ref int primefactor1, 13 ref int primefactor2) primefactor1 = 1; 16 primefactor2 = number; // Factorize using a low tech approach. 19 for (int i=2;i<number;i++) if (0 == (number % i)) primefactor1 = i; 24 primefactor2 = number / i; 25 break; if (1 == primefactor1 ) 29 return false; 30 else 31 return true ; // Create an asynchronous delegate that matches the Factorize method. 36 public delegate bool AsyncFactorCaller ( 37 int number, 38 ref int primefactor1, 39 ref int primefactor2); public class DemonstrateAsyncPattern // The waiter object used to keep the main application thread 44 // from terminating before the callback method completes. 45 ManualResetEvent waiter; // Dene the method that receives a callback when the results are available. 26 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

27 3.5 Delegaten 48 public void FactorizedResults(IAsyncResult result) int factor1=0; 51 int factor2=0; // Extract the delegate from the 54 // System.Runtime.Remoting.Messaging.AsyncResult. 55 AsyncFactorCaller factordelegate = (AsyncFactorCaller)((AsyncResult)result).AsyncDelegate; 56 int number = (int) result.asyncstate; 57 // Obtain the result. 58 bool answer = factordelegate.endinvoke(ref factor1, ref factor2, result); 59 // Output the results. 60 Console.WriteLine("On CallBack: Factors of 0 : 1 2-3", 61 number, factor1, factor2, answer); 62 waiter.set(); // The following method demonstrates the asynchronous pattern using a callback method. 66 public void FactorizeNumberUsingCallback() AsyncFactorCaller factordelegate = new AsyncFactorCaller (PrimeFactorFinder.Factorize); 69 int number = ; 70 int temp=0; 71 // Waiter will keep the main application thread from 72 // ending before the callback completes because 73 // the main thread blocks until the waiter is signaled 74 // in the callback. 75 waiter = new ManualResetEvent(false); // Dene the AsyncCallback delegate. 78 AsyncCallback callback = new AsyncCallback(this.FactorizedResults); // Asynchronously invoke the Factorize method. 81 IAsyncResult result = factordelegate.begininvoke( 82 number, 83 ref temp, 84 ref temp, 85 callback, 86 number); // Do some other useful work while 89 // waiting for the asynchronous operation to complete // When no more work can be done, wait. 92 waiter.waitone(); // The following method demonstrates the asynchronous pattern 96 // using a BeginInvoke, followed by waiting with a time out. 97 public void FactorizeNumberAndWait() AsyncFactorCaller factordelegate = new AsyncFactorCaller (PrimeFactorFinder.Factorize); int number = ; 102 int temp=0; // Asynchronously invoke the Factorize method. 105 IAsyncResult result = factordelegate.begininvoke( 106 number, 107 ref temp, 108 ref temp, 109 null, 110 null); while (!result.iscompleted) // Do any work you can do before waiting. 115 result.asyncwaithandle.waitone(10000, false); // The asynchronous operation has completed. 118 int factor1=0; 119 int factor2=0; // Obtain the result. 122 bool answer = factordelegate.endinvoke(ref factor1, ref factor2, result); c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

28 3.6 Attribute und Reektion 124 // Output the results. 125 Console.WriteLine("Sequential : Factors of 0 : 1 2-3", 126 number, factor1, factor2, answer); public static void Main() DemonstrateAsyncPattern demonstrator = new DemonstrateAsyncPattern(); 132 demonstrator.factorizenumberusingcallback(); 133 demonstrator.factorizenumberandwait(); Delegate: Ein Delegate deniert einen neuen Typ, der Referencen auf Methoden enthält. Ereignisse nutzen Delegate, um Objekte über das Eintreten des Ereignisses zu informieren. Alle Abonnenten (Subscriber) des Ereignisses werden informiert. Ein Callback 5 deniert eine Beziehung zwischen zwei Klassen. Ein Callback ist ein Pattern. Ein Callback wird nicht in die Welt rauspossaunt, sondern bleibt für sich. Die Beziehung sorgt dafür, dass ein Objekt automatisch auf ein anderes Objekt reagiert. 3.6 Attribute und Reektion Abbildung 3.5: Reektion und Attribute Attribute stellen eine eziente Methode dar, um Deklarationsinformationen mit C#-Code (Typen, Methoden, Eigenschaften usw.) zu verknüpfen. Sobald das Attribut einer Programmentität zugeordnet ist, kann es zur Laufzeit mithilfe eines Verfahrens abgefragt werden, das als Reektion bezeichnet wird Attribute Attribute fügen dem Programm Metadaten hinzu. Metadaten sind Informationen zu den in einem Programm denierten Typen. Alle.NET-Assemblys enthalten einen angegebenen Satz von Metadaten, die die in der Assembly denierten Typen und Typmember beschreiben. Sie können benutzerdenierte Attribute hinzufügen, um bei Bedarf zusätzliche Informationen anzugeben. 5 Der Begri Callback (Rückruf) wird in verschiedene Programmiermodellen verwendet als Begri für die Möglichkeit, dass aufgerufener Programmcode seinerseits einen Aufruf zu dem Aufrufer startet. Ein Callback ist eine asynchrone Operation im Gegensatz zu einem Rückgabewert auf einen Aufruf. 28 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

29 3.6 Attribute und Reektion Sie können eigene benutzerdenierte Attribute erstellen, indem Sie eine Attributklasse denieren. Dies ist eine Klasse, die direkt oder indirekt Elemente von Attribute ableitet, wodurch die schnelle und einfache Identikation von Attributdenitionen in Metadaten ermöglicht wird. Angenommen, Sie möchten Klassen und Strukturen mit dem Namen des Programmierers kennzeichnen, der sie geschrieben hat. Sie könnten beispielsweise eine benutzerdenierte Author-Attributklasse denieren: Der Klassenname entspricht dem Attributnamen, also Author. Da er von System.Attribute abgeleitet ist, handelt es sich um eine benutzerdenierte Attributklasse. Die Parameter des Konstruktors sind die positionellen Parameter des benutzerdenierten Attributs (in diesem Fall name), und alle öentlichen Felder oder Eigenschaften, die Lese- und Schreibzugri unterstützen, sind benannte Parameter (in diesem Fall ist version der einzige benannte Parameter). Beachten Sie, dass das AttributeUsage-Attribut verwendet wird, um die Gültigkeit des Author-Attributs auf class- und struct-deklarationen zu beschränken Reektion Metadaten eines Moduls können zur Laufzeit ausgelesen und geändert werden Diesen Vorgang nennt man Reektion.NET Framework stellt entsprechende Klassen über den Namespace System.Reection bereit 6 Bei der Reektion werden Objekte (vom Typ Type) bereitgestellt, die Assemblys, Module und Typen beschreiben. Mithilfe von Reektion können Instanzen von Typen dynamisch erzeugt, Typen an ein vorhandenes Objekt gebunden und Typinformationen von vorhandenen Objekten abgefragt werden. Ebenso können die Methoden vorhandener Objekte aufgerufen werden, und es kann auf ihre Felder und Eigenschaften zugegrien werden. Wenn Sie Attribute im Code verwenden, können Sie mithilfe von Reektion auf diese Attribute zugreifen. Reektion ist in folgenden Situationen nützlich: Wenn Sie auf Attribute in den Metadaten des Programms zugreifen müssen. Für das Überprüfen und das Instanziieren von Typen in einer Assembly. Für das Erstellen neuer Typen zur Laufzeit. Verwenden Sie die Klassen in System.Reection.Emit. Für das Ausführen von spätem Binden und für den Zugri auf Methoden von zur Laufzeit erstellten Typen Zugri auf Attribute mit Reektion Listing 3.23: Benutzerdeniertes Attribute und Reektion //Denition [System.AttributeUsage(System.AttributeTargets.Class System.AttributeTargets.Struct, AllowMultiple = true) // multiuse attribute ] public class Author : System.Attribute string name; public double version; public Author(string name) this.name = name; version = 1.0; // Default value public string GetName() return name; [Author("H. Ackerman")] private class FirstClass //... // No Author attribute private class SecondClass 6 Reektion 29 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

30 3.7 Lambda-Ausdrücke //... [Author("H. Ackerman"), Author("M. Knott", version = 2.0)] private class ThirdClass //... class TestAuthorAttribute static void Main() PrintAuthorInfo(typeof(FirstClass)); PrintAuthorInfo(typeof(SecondClass)); PrintAuthorInfo(typeof(ThirdClass)); private static void PrintAuthorInfo(System.Type t) System.Console.WriteLine("Author information for 0", t); System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t); // reection foreach (System.Attribute attr in attrs) if (attr is Author) Author a = (Author)attr; System.Console.WriteLine(" 0, version 1:f", a.getname(), a.version); Aufgabe 3.7 Welche Ausgabe erzeugt das Programm? 3.7 Lambda-Ausdrücke Bei einem Lambda-Ausdruck handelt es sich um eine anonyme Funktion, die Ausdrücke und Anweisungen enthalten und für die Erstellung von Delegaten oder Ausdrucksbaumstrukturen verwendet werden kann. Alle Lambda-Ausdrücke verwenden den Operator Lambda =>, der so viel bedeutet wie wechselt zu. Auf der linken Seite des Operators Lambda werden die Eingabeparameter angegeben (falls vorhanden), und auf der rechten Seite bendet sich der Ausdruck oder Anweisungsblock. Der Lambda-Ausdruck x => x * x bedeutet x wechselt x Mal zu x. Dieser Ausdruck kann wie folgt einem Delegattyp zugewiesen werden: (input parameters) => expression //Beispiele (x, y) => x == y n => n<5 Listing 3.24: Ausdruckslambdas Listing 3.25: Anweisungslambdas (input parameters) => statement; //Beispiel : n => string s = n + " " + "World"; Console.WriteLine(s); 3.8 IDisposable IDisposable deniert eine Methode zur Freigabe von reservierten Ressourcen. Über diese Schnittstelle werden hauptsächlich nicht verwaltete Ressourcen freigegeben. Der Garbage Collector gibt automatisch den für ein 30 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

31 3.8 IDisposable verwaltetes Objekt reservierten Speicher frei, wenn dieses Objekt nicht mehr verwendet wird. Es kann allerdings nicht vorausgesagt werden, wann die Garbage Collection stattndet. Darüber hinaus hat der Garbage Collector keine Kenntnis von nicht verwalteten Ressourcen wie Fensterhandles oder oenen Dateien und Streams. Mit der Dispose-Methode dieser Schnittstelle können nicht verwaltete Ressourcen in Verbindung mit dem Garbage Collector explizit freigegeben werden. Der Consumer eines Objekts kann diese Methode aufrufen, wenn das Objekt nicht mehr benötigt wird. Verwenden Sie für den Aufruf einer Klasse, die die IDisposable-Schnittstelle implementiert, einen try-nally-block, um sicherzustellen, dass nicht verwaltete Ressourcen auch dann freigegeben werden, wenn die Anwendung aufgrund einer Ausnahme beendet wird. Das Muster zum Verwerfen eines Objekts, Dispose-Muster genannt, legt eine Ordnung für die Lebensdauer von Objekten fest. Die Dispose-Methode eines Typs sollte alle Ressourcen freigeben, die dieser besitzt. Sie sollte auÿerdem alle Ressourcen freigeben, deren Eigentümer die Basistypen der Methode sind, indem die Dispose-Methode des übergeordneten Typs aufgerufen wird. Die Dispose-Methode des übergeordneten Typs sollte alle Ressourcen freigeben, die dieser besitzt, und dann die Dispose-Methode seines übergeordneten Typs aufrufen. Dieses Muster wird durch die Hierarchie der Basistypen weitergegeben. Um sicherzustellen, dass Ressourcen immer entsprechend bereinigt werden, sollte eine Dispose-Methode auch mehrmals aufgerufen werden können, ohne eine Ausnahme auszulösen. Durch das Implementieren der Dispose-Methode für Typen, die nur verwaltete Ressourcen (z. B. Arrays) verwenden, werden keine Leistungsvorteile erzielt, da diese automatisch vom Garbage Collector freigegeben werden. Verwenden Sie die Dispose-Methode primär für verwaltete Objekte, die systemeigene Ressourcen verwenden, und für COM-Objekte, die für.net Framework verfügbar sind. Verwaltete Objekte, die systemeigene Ressourcen (z. B. die FileStream-Klasse) verwenden, implementieren die IDisposable-Schnittstelle. Eine Dispose-Methode sollte die SuppressFinalize-Methode für das Objekt aufrufen, das es freigibt. Wenn sich das Objekt gegenwärtig in der Finalisierungswarteschlange bendet, verhindert SuppressFinalize, dass dessen Finalize-Methode aufgerufen wird. Beachten Sie, dass das Ausführen einer Finalize-Methode hohen Leistungsaufwand erfordert. Wenn Sie das Objekt bereits mit der Dispose-Methode bereinigt haben, muss die Finalize- Methode des Objekts nicht mehr vom Garbage Collector aufgerufen werden. Im folgenden Codebeispiel wird das empfohlene Entwurfsmuster für das Implementieren einer Dispose-Methode für Klassen veranschaulicht, die nicht verwaltete Ressourcen kapseln. Ressourcenklassen werden i. d.r. von komplexen systemeigenen Klassen oder APIs abgeleitet und müssen entsprechend angepasst werden. Verwenden Sie dieses Codemuster als Anfangspunkt zum Erstellen einer Ressourcenklasse, und stellen Sie die erforderliche Anpassung basierend auf den Ressourcen, die Sie kapseln, bereit. //Klasse, die IDisposable implementiert. public class DisposableResource : IDisposable private Stream resource; private bool disposed; Listing 3.26: Dispose-Pattern // The stream passed to the constructor // must be readable and not null. public DisposableResource(Stream stream) if (stream == null) throw new ArgumentNullException("Stream in null."); if (!stream.canread) throw new ArgumentException("Stream must be readable."); resource = stream; disposed = false; // Demonstrates using the resource. // It must not be already disposed. public void DoSomethingWithResource() if (disposed) throw new ObjectDisposedException("Resource was disposed."); // Show the number of bytes. 31 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

32 3.9 using int numbytes = (int) resource.length; Console.WriteLine("Number of bytes: 0", numbytes.tostring()); public void Dispose() Dispose(true); // Use SupressFinalize in case a subclass // of this type implements a nalizer. GC.SuppressFinalize(this); protected virtual void Dispose(bool disposing) // If you need thread safety, use a lock around these // operations, as well as in your methods that use the resource. if (!disposed) if (disposing) if (resource!= null) resource.dispose(); Console.WriteLine("Object disposed."); // Indicate that the instance has been disposed. resource = null; disposed = true; //Aufrufende Klasse class Program static void Main() try // Initialize a Stream resource to pass // to the DisposableResource class. Console.Write("Enter filename and its path: "); string filespec = Console.ReadLine(); FileStream fs = File.OpenRead(fileSpec); DisposableResource TestObj = new DisposableResource(fs); // Use the resource. TestObj.DoSomethingWithResource(); // Dispose the resource. TestObj.Dispose(); catch (FileNotFoundException e) Console.WriteLine(e.Message); 3.9 using using 7 stellt eine intuitive Syntax bereit, die die richtige Verwendung von IDisposable-Objekten sicherstellt. Wenn Sie ein IDisposable-Objekt verwenden, sollten Sie es grundsätzlich deklarieren und in einer using- Anweisung instanziieren. Die using-anweisung ruft die Dispose-Methode für das Objekt auf die richtige Weise auf und (bei Verwendung wie oben gezeigt) verursacht, dass das Objekt seinen Gültigkeitsbereich verlässt, 7 using-anweisung 32 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

33 3.10 Serialisierung sobald Dispose aufgerufen wird. Innerhalb des using-blocks ist das Objekt schreibgeschützt und kann nicht geändert oder neu zugewiesen werden. Mit der using-anweisung wird sichergestellt, dass Dispose auch aufgerufen wird, wenn ein Ausnahmefehler auftritt, während Sie Methoden für das Objekt aufrufen. Sie erzielen dasselbe Ergebnis, indem Sie das Objekt in einen try-block einfügen und Dispose in einem nally-block aufrufen. Auf diese Weise wird die using-anweisung vom Compiler übersetzt. Der Code im oben gezeigten Beispiel wird bei der Kompilierung auf folgenden Code erweitert (beachten Sie die zusätzlichen geschweiften Klammern zur Erstellung des begrenzten Gültigkeitsbereichs für das Objekt): Listing 3.27: using using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\Users\Public\Documents\test.txt")) string s = null; while((s = sr.readline())!= null) Console.WriteLine(s); Aufgabe 3.8 Fügen Sie in Listing 3.27 das Werfen einer Ausnahme innerhalb des using-blocks ein. Was passiert? Schauen Sie sich den Ablauf im Debugger an Serialisierung 8 Serialisierung beschreibt den Vorgang des Konvertierens eines Objekts in eine Form, die problemlos transportiert werden kann. So können Sie beispielsweise ein Objekt serialisieren und es über das Internet per HTTP zwischen einem Client und einem Server transportieren. Am anderen Ende wird das Objekt durch Deserialisierung aus dem Stream wiederhergestellt. Bei der XML-Serialisierung werden nur die öentlichen Felder und Eigenschaftenwerte eines Objekts in einen XML-Stream serialisiert. Typinformationen werden bei der XML-Serialisierung nicht berücksichtigt. Wenn Sie z. B. über ein Book-Objekt im Library-Namespace verfügen, wird es nicht in jedem Fall in ein Objekt desselben Typs deserialisiert. Wenn Sie ein Objekt serialisieren möchten, erstellen Sie zuerst das zu serialisierende Objekt, und legen Sie dann dessen öentliche Eigenschaften und Felder fest. Dazu müssen Sie das Transportformat angeben, in dem der XML-Stream gespeichert werden soll: als ein Stream oder als eine Datei. Wenn der XML-Stream beispielsweise in einer permanenten Form gespeichert werden muss, erstellen Sie ein FileStream-Objekt. Listing 3.28: Attribut Serializable //Zustand ablegen MySerializableClass myobject = new MySerializableClass(); // Insert code to set properties and elds of the object. XmlSerializer myserializer = new XmlSerializer(typeof(MySerializableClass)); // To write to a le, create a StreamWriter object. StreamWriter mywriter = new StreamWriter("myFileName.xml"); myserializer.serialize(mywriter, myobject); mywriter.close(); //Zustand wieder herstellen MySerializableClass myobject; // Construct an instance of the XmlSerializer with the type // of object that is being deserialized. XmlSerializer myserializer = new XmlSerializer(typeof(MySerializableClass)); // To read the le, create a FileStream. FileStream myfilestream = new FileStream("myFileName.xml", FileMode.Open); // Call the Deserialize method and cast to the object type. myobject = (MySerializableClass) myserializer.deserialize(myfilestream) Weitere Beispiele nden Sie unter Beispiele für die XML-Serialisierung. 8 Einführung in die XML-Serialisierung 33 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

34 3.11 XML-Dokumentationskommentare 3.11 XML-Dokumentationskommentare In Visual C# lässt sich eine Dokumentation des Codes erstellen. Dazu werden XML-Tags in spezielle Kommentarfelder des Quellcodes unmittelbar vor dem Codeblock eingefügt, auf den sie sich beziehen. Wenn Sie mit /doc kompilieren, sucht der Compiler alle XML-Tags im Quellcode und erstellt eine XML-Dokumentationsdatei. XML-Dokumentkommentare sind keine Metadaten und sind nicht in der kompilierten Assembly enthalten. Folglich ist der Zugri auf sie über Reektion nicht möglich. Wenn Sie in der IDE /// vor einem Codeblock eingeben, erzeugt Ihnen VS automatisch einen passenden Kommentar. Möchten Sie zusammenhängende Methoden, z.b. ctor (Konstruktoren), private Methoden o.ä. einfach ein- und ausklappen können, so verwenden Sie #region ctor... #endregion Namenskonventionen Nach dem Naming Guideline von Microsoft sollen Parameter, Klassen etc. wie folgt benannt werden, Basis ist PascalCase und camelcase: Nur Parameter und private Members sind camelcase Namespace:CompanyName.TechnologyName[.Feature][.Design], Beispiel: Microsoft.Media.Design Klassen: Nomen, Beispiel: class FileStream Methoden: Verben, Beispiel: RemoveAll() Interfaces: Nomen oder Nomenausdrücke, Beispiel: IServiceProvider, IFormatable Diese Namensrichtlinien können Sie mit StyleCop validieren. Auf Assembly-Ebene analysiert das Werkzeug FxCop vorwiegend Designkonventionen für Entwicklerinnen von Klassenbibliotheken (Design Guidelines for Class Library Developers), aber auch einige Namenskonventionen. Sie können natürlich auch einer anderen Richtlinie wie Zend für PHP folgen. Machen Sie dies in der Dokumentation Ihres Codes deutlich Aufgaben Die Aufgaben stammen von.net AT JKU. Aufgabe 3.9 Was sind die Vorteile eines Enumerationstyps (z.b. enum Color red, blue, green) gegenüber int- Konstanten (z.b. const int red = 0, blue = 1, green = 2;)? Aufgabe 3.10 Studieren Sie die Klasse Enum aus der Online-Dokumentation des.net-sdk und schreiben Sie zwei Methoden zur Ein- und Ausgabe von Werten eines von Ihnen gewählten Enumerationstyps in textueller Form. Können Sie die Methoden so allgemein halten, dass Sie damit Werte eines beliebigen Enumerationstyps lesen und schreiben können? Aufgabe 3.11 Schreiben Sie eine Methode double[,] MatrixMult(double[,] a, double[,] b) die zwei Matrizen a und b multipliziert und das Ergebnis als Funktionswert liefert. Wenn sich a und b auf Grund ihrer Dimensionen nicht multiplizieren lassen, soll die Methode eine Ausnahme liefern. allgemein halten, dass Sie damit Werte eines beliebigen Enumerationstyps lesen und schreiben können? Aufgabe 3.12 Schreiben Sie eine Methode, die aus einem Pfadnamen (z.b. c: dotnet samples myfile.cs) den Dateinamen ohne Verzeichnisse und Dateiendung herausschält (z.b. myfile). Aufgabe 3.13 Schreiben Sie eine switch-anweisung, die zu einem gegebenen Monat die Anzahl seiner Tage berechnet (ohne Schaltjahre zu berücksichtigen). Implementieren Sie eine Version, bei der das Monat durch eine Zahl gegeben ist und eine andere, bei der es durch einen String gegeben ist. Vergleichen Sie den erzeugten Code mittels ildasm. 34 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

35 3.13 Aufgaben Aufgabe 3.14 Erzeugen Sie eine Tabelle der Quadrate und Wurzeln der ersten n natürlichen Zahlen. Verwenden Sie dazu formatierte Ausgabe. Zur Berechnung der Wurzel können Sie die Funktion Math.Sqrt verwenden. Übergeben Sie n als Kommandozeilenparameter. Aufgabe 3.15 Für welche Aufgaben würden Sie Klassen verwenden, für welche Structs? Nennen Sie Beispiele. Aufgabe 3.16 Implementieren Sie einen Struct Complex zum Rechnen mit komplexen Zahlen. Sehen Sie geeignete Konstruktoren vor sowie Properties, um auf dem reellen und imaginären Teil einer komplexen Zahl zugreifen zu können. Implementieren Sie mittels Operator Overloading die Addition, Multiplikation und den Vergleich komplexer Zahlen. Sehen Sie auch einen impliziten und einen expliziten Konversionsoperator vor, mit dem man zwischen komplexen Zahlen und double konvertieren kann. Überschreiben Sie schlieÿlich auch die von Object geerbten Methoden Equals, ToString und GetHashCode. Aufgabe 3.17 Implementieren Sie eine Klasse GrowableArray, die ein dynamisch wachsendes Array beliebiger Objekte darstellt. Ein Indexer soll den Zugri auf die einzelnen Elemente erlauben. Wird über einen Index zugegrien, der gröÿer als die bisherige Arraylänge ist, so soll das Array dynamisch erweitert, d.h. durch ein längeres ersetzt werden, wobei die Werte des alten Arrays den Anfang des neuen Arrays bilden sollen. Aufgabe 3.18 Erweitern Sie Ihre Klasse GrowableArray so, dass die Elemente im Array mittels einer foreach- Schleife durchlaufen werden können. Dazu muss GrowableArray das Interface IEnumerable implementieren. Studieren Sie dieses Interface in der Online-Dokumentation des.net-sdk. Aufgabe 3.19 Schreiben Sie eine Klasse In mit Methoden zum Lesen von Zahlen, Wörtern, Strings, Zeichen und Booleschen Werten von der Tastatur. Bauen Sie dabei auf die Klasse Console auf. Aufgabe 3.20 Erweitern Sie Ihre Klasse In so, dass man mit ihr wahlweise von der Tastatur, von einer Datei oder von einer Zeichenkette lesen kann. Aufgabe 3.21 Nehmen Sie an, man möchte wissen, wieviele Objekte einer bestimmten Klasse C im Laufe eines Programms erzeugt wurden. Implementieren Sie eine solche Klasse und versehen Sie sie mit einer statischen Zählervariablen sowie mit einer statischen Methode, mit der die Zählervariable zurückgesetzt werden kann. Wo muss die Zählervariable erhöht werden? Aufgabe 3.22 Implementieren Sie ein Struct Time zur Verwaltung von Uhrzeiten. Intern sollen Uhrzeiten in Sekunden gespeichert werden. Es soll aber drei Properties geben, die den Stunden-, Minuten-, und Sekundenanteil einer Uhrzeit liefern. Sehen Sie auch überladene Operatoren und Konstruktoren vor, um mit Uhrzeiten bequem rechnen zu können. Aufgabe 3.23 Diskutieren Sie Vor- und Nachteile von Ref-Parametern, Out-Parametern und Parametern, die als Funktionsergebnisse zurückgegeben werden. Aufgabe 3.24 Implementieren Sie eine Methode Clear, mit der eine beliebige Anzahl von Elementen eines beliebigen int-arrays auf 0 gesetzt werden kann (z.b. Clear(arr, 3, 4, 9, 12);). Aufgabe 3.25 Was ist der Unterschied zwischen einer abstrakten Klasse und einem Interface? Aufgabe 3.26 Gegeben sei ein Array von Objekten der gleichen Art (z.b. Strings, Bruchzahlen oder sonstige Objekte). Schreiben Sie eine Methode Sort(arr, compare), die das Array arr sortiert und dazu eine Vergleichsmethode compare(x, y) verwendet, die als Delegate übergeben wird und zwei Objekte x und y des Arrays miteinander vergleicht, d.h. feststellt, ob x gröÿer, kleiner oder gleich y ist. Aufgabe 3.27 Implementieren Sie eine Zählerklasse Counter mit einer Methode Add(x) zum Erhöhen des Zählerwerts und einer Methode Clear() zum Löschen des Zählerwerts. Wenn der Zählerwert eine bestimmte Bedingung erfüllt (z.b. Zählerwert > n) sollen eine oder mehrere Aktionen ausgelöst werden. Sowohl die Bedingung als auch die Aktionen sollen als Delegates an die Zählerklasse übergeben werden können. Aufgabe 3.28 Schreiben Sie eine Methode static void Plot (Function f)... der man eine Funktion eine Delegate-Typs delegate double Function(double x); übergeben kann und die ein zweidimensionales Diagramm dieser Funktion zeichnet. Verwenden Sie der Einfachheit halber als Grak eine zweidimensionale char-matrix. 35 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

36 3.13 Aufgaben Aufgabe 3.29 Die Methode Convert.ToInt32(s) konvertiert eine im String s gespeicherte Zahlenfolge in eine int-zahl. Dabei können verschiedene Ausnahmen auftreten, wenn s nicht das richtige Format hat oder keinen gültigen Wert enthält. Studieren Sie die möglichen Ausnahmen in der.net-sdk-dokumentation und schreiben Sie ein Programm, in dem diese Ausnahmen durch eine try-catch-anweisung abgefangen werden. Aufgabe 3.30 Implementieren Sie eine sortierte verkettete Liste mit den Operationen Add(x) und Remove(x) sowie mit einem Property Count, das die Anzahl der Elemente der Liste liefert. Auÿerdem soll es einen Indexer geben, mit dem man auf jedes Listenelement zugreifen kann. Der Typ der Listenelemente soll beliebig sein. Aufgabe 3.31 Schreiben Sie einen generischen binären Suchbaum BinaryTree<K, V>, der Werte vom Typ V unter ihrem Schlüssel vom Typ K speichert. Sehen Sie eine Methode Insert vor, mit der man ein Schlüssel/Wert- Paar in den Baum einfügen kann, sowie eine Methode Contains, die prüft, ob ein bestimmter Schlüssel im Baum enthalten ist. Schreiben Sie auch einen Indexer, der den Wert zu einem gegebenen Schlüssel liefert oder eine Ausnahme auslöst, wenn der Schlüssel nicht gefunden wurde. Aufgabe 3.32 Verwenden Sie den in der Online-Dokumentation von.net beschriebenen Typ List<T>, um eine Liste von Wortlisten anzulegen. Lesen Sie einen Text aus mehreren Zeilen, wobei jede Zeile aus mehreren Wörtern (Buchstabenfolgen) besteht. Alle Wörter einer Zeile sollen in einer Liste vom Typ List<string> gespeichert werden. Bilden Sie dann aus den Wortlisten der einzelnen Zeilen wiederum eine Liste vom Typ List<List<string. Aufgabe 3.33 Schreiben Sie eine generische Methode list = Copy(array), die ein Array beliebigen Elementtyps in eine generische Liste gleichen Elementtyps kopiert. Verwenden Sie als Listentyp List<T> (siehe Online- Dokumentation von.net). Aufgabe 3.34 Implementieren Sie eine Klasse zur Verwaltung einer verketteten Liste von Namen (Strings). Sehen Sie folgende Iteratoren vor: Eine allgemeine Iterator-Methode, die alle in der Liste gespeicherten Namen liefert. Eine spezische Iterator-Methode, die nur jene Namen der Liste liefert, die mit einem bestimmten String beginnen. Der String soll als Parameter mitgegeben werden. Ein Iterator-Property, das nur jene Namen der Liste liefert, die länger als 5 Buchstaben sind. Aufgabe 3.35 Versehen Sie eine von Ihnen implementierte Klasse mit XML-Kommentaren und sehen Sie sich an, was der Compiler daraus erzeugt, wenn er mit der Option /doc:myfile.xml aufgerufen wird. 36 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

37 4 Komponenten 1 In der Softwarebranche wird mit dem Begri Komponente ein wiederverwendbares Objekt bezeichnet, das für Clients auf standardisierte Art eine oder mehrere Schnittstellen verfügbar macht. Zu den am häugsten verwendeten Komponenten im Bereich der.net Framework-Programmierung zählen die visuellen Steuerelemente, die Windows Forms hinzugefügt werden. Wird eine Komponente in C# erstellt, kann diese auch von Clients verwendet werden, die in einer anderen Sprache geschrieben sind, die der CLS (Common Language Specication) entspricht dabei ist hervorzuheben, dass die Komponenten sich durch ihre Attribute selbst beschreibt und somit keine globale Registrierung zwingend erforderlich ist. Die Anwendung, die eine solche Komponente nutzen möchte, muss lediglich das zugehörige Assembly einbinden. 2 Während der Begri Komponente viele Bedeutungen hat, ist im.net Framework eine Komponente eine Klasse, die das Interface IComponent implementiert (oder von einer solchen Klasse abgeleitet ist). Ohne diese engere Denition könnte man jedes Assembly als Komponente bezeichnen. Wobei, wenn man schaut, welche Klassen IComponent implementieren, so ist man nicht weit davon entfernt.... System.ComponentModel.Component: Basisimplemantation von IComponent typische Basisklasse für nicht-visuelle Komponenten System.Web.UI.Control: Basisklasse für alle ASP.NET-Controls, implementiert IComponent direkt System.Windows.Forms.Control: erbt von System.ComponentModel.Component und ist die Basisklasse für alle WinForm-Controls System.Data.DataSet: erbt von System.ComponentModel.MarshalByValueComponent implementiert IComponent. System.Diagnostics.EventLog: erbt von System.ComponentModel.Component. Abbildung 4.1: IComponent Quelle: Leveraging.NET Components Dies liegt vermutlich daran, dass IComponent nicht viel vorgibt: IComponent implementiert IDisposable public property: ISiteSiteget; set; mit ISite erbt von IServiceProvider: ObjectGetService(T ypeservicet ype) Ruft das Dienstobjekt des angegebenen Typs ab. IComponentComponentget; Ruft bei der Implementierung durch eine Klasse die der ISite zugeordnete Komponente ab. IContainerContainerget; Ruft bei der Implementierung durch eine Klasse den der ISite zugeordneten Container ab. IContainer stellt Add, Dispose, Remove zur Verfügung. booldesignm odeget; Bestimmt bei der Implementierung durch eine Klasse, ob sich die Komponente im Entwurfsmodus bendet. 1 Erstellen von Komponenten 2 Programmieren mit Komponenten 37

38 4 Komponenten stringnameget; set; Ruft bei der Implementierung durch eine Klasse den Namen der Komponente ab, die ISite zugeordnet ist, oder legt diesen fest. public event: eventeventhandlerdisposed; public method, von IDisposable: voiddispose() Komponente: Jede Komponente in.net implementiert das Interface IComponent. Unter einem Control versteht Microsoft eine UI-Komponente, diese werden von eine der zwei Klassen System.Windows.Forms.Control oder System.Web.UI.Control abgeleitet. Abbildung 4.2 zeigt die zugehörigen Interfaces und die Objekthierarchie Container 3. Abbildung 4.2: Control Control vs Komponente: Jedes Control ist eine Komponente, aber nicht jede Komponente ist ein Control. Das Thema sinnvoll abzugrenzen und zu strukturieren ist schwierig. Aufgrund der historischen Entwicklung gibt es viele Begrie und Technologien: COM, ActiveX, Add-In, Excel-Addin, Plugin,... COM Das Component Object Model (COM) ist Microsofts Ansatz für objektorientierte Softwarekomponenten. Das.NET Framework sollte ursprünglich COM 3.0 heiÿen. COM-Komponenten müssen in die Registry eingetragen werden. COM basiert auf dem Client/Server-Prinzip. COM läuft nur unter Windows. DCOM Distributed COM, Komponentenkommunikation über Prozess- und Maschinengrenzen hinweg möglich. ActiveX ActiveX ist ein Dienst auf Basis von COM und DCOM. ActiveX-Control Früher wurden diese Steuerelemente auch OLE-Steuerelemente bzw. OCXes (OLE Custom Controls) genannt. Es existieren viele COM-Komponenten, die in.net genutzt werden sollen/müssen. Hier trit man auf COM- Interop. Bis Sie mit dem Studium fertig sind, existiert dieses Problem hoentlich nicht mehr ;-) An dieser Stelle sei jedoch erwähnt, Microsoft bietet eine Brücke zwischen.net und COM an und die Abbildung von Parametertypen in COM nach.net ist ein Problem. Wann immer man eine Applikation mit fremden Komponenten zur Laufzeit erweitert, steht man vor folgenden Problemen: Discovery: Komponente aunden Laden und Entladen (freigeben) Absichern der Host-Anwendung 3 Custom Design-time Control 38 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

39 4.1 Eigene GUI Steuerelemente gegen Fehler in der Komponente deren Daten und Prozesse Versionierung.Net bietet hierfür zwei Frameworks, wie man eigene Applikationen für fremde Komponenten zur Laufzeit önen kann. Microsoft verfolgt diese Ansätze selbst in den Oce-Produkten und in Visual Studio. Beide Frameworks können auch kombiniert werden dies geschieht z.b. in VS2010. Doch schauen wir uns zunächst die visuellen Komponenten an, die zur Designzeit in die Applikation eingebunden werden. 4.1 Eigene GUI Steuerelemente 4 Wenn Sie ein neues Steuerelement entwerfen, müssen Sie zuerst festlegen, welche programmiertechnischen Mittel dazu eingesetzt werden sollen. Unter.NET gibt es drei unterschiedliche Szenarien: Sie erweitern ein existierendes Steuerelement durch Ableitung um spezische Funktionalitäten. Ähnlich, wie Sie eine benutzerdenierte Form erstellen, die aus Form abgeleitet ist, können Sie auch ein vorhandenes Steuerelement ableiten, um daraus eine eigene Klasse zu erstellen. Sie brauchen die abgeleitete Klasse nur um die Fähigkeiten zu erweitern, die Sie von Ihrem Steuerelement erwarten. Sie kombinieren mehrere existierende Steuerelemente zu einem neuen. Dazu stellt die Klasse UserControl einen Container bereit, der einem Panel ähnelt. Diesem Container lassen sich mehrere Steuerelemente aus der Toolbox hinzufügen, die in Kombination das neue Steuerelement bilden. Die Eigenschaften und Methoden der im UserControl enthaltenen Steuerelemente können oengelegt oder ausgeblendet werden. UserControl ist ein Steuerelement und von Control abgeleitet. Es veröentlicht daher seinerseits bereits alle von der Basis geerbten Member. Die beiden vorgenannten Entwicklungsmöglichkeiten basierten auf vorhandenen Steuerelementen. Wollen Sie ein vollkommen neues Steuerelement entwickeln, müssen Sie die Klasse Control ableiten. Das bedeutet aber auch, dass Sie die grasche Darstellung des Steuerelements selbst in die Hand nehmen müssen, da es dafür keine Basiskomponenten gibt. Wenn Sie bedenken, dass allein schon die Aktivierung eines Steuerelements eine Änderung der Darstellung zur Laufzeit bewirkt, können Sie sich vermutlich vorstellen, dass der Aufwand beträchtlich ist. Für welche Alternative Sie sich entscheiden, hängt letztendlich von den Anforderungen an das neue Steuerelement ab. Wann immer es aber möglich ist, sollten Sie auf existierende und damit letztendlich auch auf bewährte Komponenten zurückgreifen. Sie sparen damit nicht nur Entwicklungszeit, sondern auch die Zeit für ausgiebige Tests. 4.2 Managed Extensibility Framework (MEF) 5 MEF ist eine Bibliothek die das Problem der Erweiterbarkeit zur Laufzeit (Runtime Extinsibility) löst. Sie vereinfacht die Implementierung von Erweiterbaren Anwendungen und bietet Ermittlung von Typen, Erzeugung von Instanzen und Composition Fähigkeiten an. Die wichtigste Module im Core der Bibliothek sind Catalog und CompositionContainer. Das Catalog kontrolliert das Laden von Komponenten, während das Composition- Container die Instanzen erzeugt und diese an die entsprechenden Variablen bindet. Parts sind die Objekte die vom Type Export oder Import sein können. Die Exports sind im beschriebenen Beispiel die Komponenten, die geladen und instanziiert werden sollen. Die Imports sind die Variablen an die die Instanzen von der Komponenten gebunden werden sollen. Zum Beispiel wäre die bereits erwähnte Komponente Component1 in der MEF-Anwendung ein Export. Die Variable proxy vom Type IComponent die die Instanz dieser Komponente enthalten soll, wäre ein Import. MEF gibt es erst mit.net 4.0, also der aktuellen Version. Hiermit soll es leichter werden, Applikationen zu erweitern. Leichter bringt leider auch Nachteile mit sich, wie z.b. Es wird keine Isolation in AppDomains unterstützt. Es wird kein dediziertes Berechtigungssystem unterstützt. Es wird keine Versionierung unterstüzt. 4 Steuerelemente entwickeln 5 Managed Extensibility Framework 39 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

40 4.3 Managed Add-in Framework (MAF) Abbildung 4.3: MEF Whitepaper und weitere Informationen zu diesem Framework nden Sie unter Welcome to the MEF community site. 4.3 Managed Add-in Framework (MAF) MAF gibt es seit.net 3.5, also schon länger als MEF. MAF unterstützt Versionierung und verschiedene App- Domains, ist jedoch, wie wir gleich sehen werden, deutlich komplexer in der Architektur. Microsoft liefert eine Vielzahl von Produkten für sehr unterschiedliche Benutzergruppen. Individualisierte Lösungen werden anderen Unternehmen überlassen. So gibt es viele Unternehmen auf dem Markt, die Oce-Produkte für die Bedürfnisse ihrer Kunden anpassen und Komponente entwickeln, um Oce mächtiger zu machen. Für die Kunden bedeutet dies, dass sie sich nicht in eine weitere Umgebung einarbeiten müssen, sondern in ihrem geliebten Excel oder Word oder... bleiben können. MIS, jetzt Infor, entwickelte beispielsweise einen OLAP-Server und erlaubte durch ein Add-In Controllern Zugri auf diesen Server. Controller können so, ähnlich wie sie es von den Pivot-Tabellen in Standard-Excel kennen, auf multidimensionalen Daten navigieren, diese analysieren und für folgende Jahre eine Planung simulieren und schlieÿlich auf den Server schreiben. Dass dies nicht in VBA geht, ist oensichtlich. Lesende oder schreibende Zugrie auf Millionen von Daten wird üblicherweise mit C++ implementiert. An der Oberäche bendet sich ein Add-In für Excel. Mit VS2010 können diese Add-Ins noch leichter implementiert werden als noch vor wenigen Jahren, denn das Objektmodell steht bereits Out-of-the-box zur Verfügung. Mit einem Add-In kann also zusätzliche Funktionalität für ein Oce-Produkt, aber auch für Visual Studio oder jedes andere für Add-Ins geönete Produkt, implementiert werden. Dieses Add-In kann auf Daten fremder Systeme, wie Webservices, SAP-Connectors, MIS-Alea oder andere zugreifen. Selbst auf dem Server kann über das Objektmodell auf Dokumente zugegrien und diese verändert werden, ohne dass Oce auf dem Server installiert sein muss. Grundlage hierfür ist das oene XML-Format, in dem Oce mittlerweile seine Dokumente ablegt. 40 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

41 4.3 Managed Add-in Framework (MAF) Abbildung 4.4: Listen Laden eines Add-Ins 6 Die folgenden Schritte ausgeführt wenn ein Benutzer ein Dokument önet, die Teil einer Microsoft Oce-Lösung ist: 1. Die Microsoft Oce-Anwendung überprüft die benutzerdenierten Dokumenteigenschaften, ob verwaltete Codeerweiterungen, die dem Dokument zugeordnet sind. Wenn es verwaltete Codeerweiterungen gibt, lädt die Anwendung VSTOEE.dll, die VSTOLoader.dll lädt. Diese sind nicht verwaltete DLLs, die die Loader- Komponenten für Visual Studio 2010 Tools for Oce Runtime sind. VSTOLoader.dll.NET Framework lädt und startet den verwalteten Hostbereich Visual Studio Tools for Oce runtime. 2. Wenn das Dokument von einem anderen Speicherort als dem lokalen Computer geönet wird, überprüft der Visual Studio Tools for Oce runtime, dass der Speicherort des Dokuments in der Liste vertrauenswürdige SpeicherorteVertrauensstellungscenter für die bestimmten Oce-Anwendung ist. Wenn der Speicherort des Dokuments nicht in einem vertrauenswürdigen Speicherort ist, die Anpassung ist nicht vertrauenswürdig und der Ladevorgang beendet hier. 3. Visual Studio Tools for Oce runtime installiert die Lösung, wenn wurde noch nicht installiert, die neuesten Anwendungs- und Bereitstellung Manifeste lädt und eine Reihe von Sicherheitsüberprüfungen führt. 4. Wenn die Anpassung auszuführenden vertrauenswürdig ist, verwendet Visual Studio Tools for Oce runtime die Bereitstellung-Manifest und Anwendungsmanifest nach Assembly Updates suchen. Wenn eine neue Version der Assembly verfügbar ist, lädt die Common Language Runtime die neue Version der Assembly zum Cache im ClickOnce auf dem Clientcomputer. 5. Visual Studio Tools for Oce runtime erstellt eine neue Anwendungsdomäne, in die die Anpassungsassembly geladen werden. 6. Visual Studio Tools for Oce runtime lädt die Anpassungsassembly in der Anwendungsdomäne. 7. Visual Studio Tools for Oce runtime Ruft den Ereignishandler Startup in die Anpassungsassembly Modell 7 )Das Add-In-Modell besteht aus einer Reihe von Segmenten, die die Add-In-Pipeline (wird auch als Kommunikationspipeline bezeichnet) bilden, die für die gesamte Kommunikation zwischen dem Add-In und dem Host verantwortlich ist. Die Pipeline ist ein symmetrisches Kommunikationsmodell aus Segmenten, die Daten zwischen einem Add-In und dessen Host austauschen. Die Entwicklung dieser Segmente zwischen dem Host und dem Add-In stellt die erforderlichen Abstraktionsebenen bereit, die die Versionsverwaltung und Isolation des Add-Ins unterstützen. 6 Architecture of Document-Level Customizations 7 Quelle: Übersicht über Add-Ins 41 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

42 4.3 Managed Add-in Framework (MAF) Abbildung 4.5: Listen Die Assemblys für diese Segmente müssen sich nicht in derselben Anwendungsdomäne benden. Sie können ein Add-In in seine eigene neue Anwendungsdomäne, in eine vorhandene Anwendungsdomäne oder sogar in die Anwendungsdomäne des Hosts laden. Sie können mehrere Add-Ins in dieselbe Anwendungsdomäne laden. Dadurch können die Add-Ins Ressourcen und Sicherheitskontexte gemeinsam nutzen. Das Add-In-Modell unterstützt und empehlt eine optionale Grenze zwischen dem Host und dem Add-In, die als Isolationsgrenze bezeichnet wird (auch unter der Bezeichnung Remotegrenze bekannt). Diese Grenze kann eine Anwendungsdomänen- oder Prozessgrenze sein. Das Vertragssegment in der Mitte der Pipeline wird in die Anwendungsdomäne des Hosts und in die Anwendungsdomäne des Add-Ins geladen. Der Vertrag deniert die virtuellen Methoden, mit denen der Host und das Add-In Typen austauschen. Um die Isolationsgrenze zu überwinden, müssen Typen entweder Verträge oder serialisierbare Typen sein. Typen, die weder Verträge noch serialisierbare Typen sind, müssen von den Adaptersegmenten in der Pipeline konvertiert werden. Die Ansichtssegmente der Pipeline sind abstrakte Basisklassen oder Schnittstellen, die dem Host und dem Add-In eine Ansicht der gemäÿ der Denition im Vertrag gemeinsam genutzten Methoden bereitstellen. Der Unterschied zwischen einem Add-In und einem Host besteht darin, dass der Host das Element ist, das das Add-In aktiviert. Der Host kann das gröÿere der beiden Elemente, wie z. B. eine Textverarbeitungsanwendung mit ihren Rechtschreibprüfungen, oder das kleinere der beiden Elemente sein, wie z. B. ein Instant Messaging- Client mit einem eingebetteten Media Player. Das Add-In-Modell unterstützt Add-Ins sowohl in Client- als auch in Serverszenarios. Beispiele für Server-Add-Ins sind Add-Ins, die Virenschutz, Spamlter und IP-Schutz für Mailserver bereitstellen. Beispiele für Client-Add-Ins umfassen Referenz-Add-Ins für Textverarbeitungsprogramme, spezielle Funktionen für Grakprogramme und Spiele sowie Virenschutz für lokale -Clients. 8 Im.NET Framework 3.5 ndet man unter dem Namespace System.AddIn ein Objektmodell mit dem man Anwendungen um ein Plug-In Modell erweitern kann. System.AddIn arbeitet hier sehr strikt mit einer Interface Denition. Die Denition ist die Grundlage für entsprechende Adapterklassen, die letztendlich dafür verantwortlich sind den View zu aktualisieren. Der View auf beiden Seiten der Pipeline ist dann einmal mit dem Host, zum anderen mit dem AddIn verbunden. Die Adapter und der Contract sind somit nicht mit dem Host und nicht mit dem AddIn direkt referenziert, sondern werden durch die System.AddIn Infrastruktur auf Basis von Attributen und Ableitungen entsprechend geladen und instanziert. Um ein Add-In zu entwickeln muÿ der Add-In Entwickler nur folgende Abhängigkeiten beachten: Man muÿ den entsprechenden View des Contracts referenzieren, eine abstrakte Basisklasse die überschrieben wird. 8.NET 3.5 Feature: System.AddIn 42 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

43 4.3 Managed Add-in Framework (MAF) Das Add-In wird noch Attributiert, um dem Framework mitzuteilen, das es sich hier um ein Add-In handelt, das über die Infrastruktur instanziert werden kann. Kopieren des Add-In Assemblies in die entsprechende Verzeichnisstruktur. Der Host kann dann das Add-In laden. Hier ein kleines Beispiel einer Add-In Implementierung. using System; using System.AddIn; using Demo.View.Addin; Listing 4.1: Add-In namespace Demo.Addin.Number2 [AddIn( "Hello World (TechTalk Version)", Version=" ")] public class TechTalkHelloWorld : HelloWorld public override string SayHelloWorld() return "Hallo TechTalk!"; HelloWorld ist der View von dem der Entwickler ableitet. Auf der Host-Seite gibt es nun den entsprechenden Aktivierungscode für Add-Ins. Hier ein Beispiel um ein Add-In zu nden und zu instanzieren. Listing 4.2: Add-In nutzen // piperoot ist das Verzeichnis in welchem die Infrastruktur sucht //tokens enthält alle verfügbaren Add Ins die das Interface HelloWorld implementiert haben. Collection<AddInToken> tokens = AddInStore.FindAddIns( typeof( HelloWorld ), piperoot ); // Code zum anzeigen der verfügbaren Add Ins und Auswahl Logik // das ausgewählte Token wird referenziert AddInToken helloworldtoken = tokens[ number - 1 ]; // Instanzieren des Add Ins //Add In in einer eigenen AppDomain im gleichen Prozess des Hosts instanziieren HelloWorld helloworld = helloworldtoken.activate<helloworld>( AddInSecurityLevel.Host ); // Nutzen des Add Ins Console.WriteLine( helloworld.sayhelloworld() ); Man erkennt schon, dass Add-Ins dementsprechend Remotable sein müssen, da.net Remoting als Kommunikationsinfrastruktur genommen wird. Um das Add-In nun in einen eigenen Prozess zu instanziieren, kann man folgende Zeilen schreiben. AddInToken helloworldtoken = tokens[ number - 1 ]; AddInProcess process = new AddInProcess(); process.start(); HelloWorld helloworld = helloworldtoken.active<hellworld>( process,addinsecuritylevel.host ); Console.WriteLine( helloworld.sayhelloworld() ); Beim Benutzen des Add-Ins wird entsprechend ein neuer Prozess hochgezogen. Die Infrastruktur stellt hierzu den Host AddInProcess32.exe zur Verfügung. Die Kommunikation zwischen dem gestarteten Prozess und dem Host läuft dann über den IPC Channel von.net Remoting. Die Inter-Process-Communication des Betriebssystems erlaubt es direkt zwischen AppDomains auf der gleichen physikalischen Maschine performant zu kommunizieren und.net Remoting bietet eben diesen Channel an, der dann auch konsequent von AddInProcess32.exe genutzt wird. Das System.AddIn Objektmodell erlaubt es nun mit relativ einfachen Mitteln, eine Plugin Architektur in eigene Anwendungen einzubauen, mit dem Vorteil der Versionierung und der Isolation durch die verfügbaren Aktivierungsmöglichkeiten. Das Hauptproblem bei der Übertragung von UI-Elementen besteht nun darin, dass die Klassen im System.Windows.Forms-Namespace nicht serialisierbar sind und somit nicht direkt übertragen werden können. Die leiten zwar von MarshalByRefObject ab, können aber auch nicht per Referenz übertragen werden. Doch wie sonst soll die Kommunikation erfolgen? Eine Lösung zum diesem Problem ist hier beschrieben Windows 43 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

44 4.3 Managed Add-in Framework (MAF) Forms Support für System.AddIn, Teil 1. Wie das in WPF funktioniert, wird hier beschrieben: Gewusst wie: Erstellen eines Add-Ins, das eine Benutzeroberäche zurückgibt. 44 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

45 5 Windows Presentation Foundation Abbildung 5.1: User Experience Viele Anwendungen werden vorwiegend von Entwicklern entworfen. Das CI designen Pros, die auch Vorgaben für Schriften und Farben der Produkte machen, das Look and Feel stammt jedoch häug von mehr oder weniger begabten Entwicklern. Sie gehen nüchtern davon aus, wenn das Produkt die tollen Features hat und diese für sie gut bedienbar sind, dann reicht das. Gerade der Erfolg von Apple zeigt, dass Begeisterung für ein Produkt etwas anderes ist. Zu diesem Thema gibt es einen ganzen Forschungszweig User Experience (UX) und Firmen investieren zunehmend in die Messung dieser Erfahrungen. Google liefert beispielsweise Treer zu diesem Begri. User-experience is not like usability - it is about feelings. The aim here is to create happiness. You want people to feel happy before, during and after they have used your product. Baekdal, Thomas Dies sind sicher hohe Ansprüche für eine nüchterne DB-Modellierungsanwendung. Dennoch ist es bei jedem gröÿeren Produkt mit dem entsprechenden Budget sinnvoll, UX zu berücksichtigen und Pros hinzuzuziehen. Mehr zu diesem Thema nden Sie z.b. unter What's new on Design IBM, An Agile approach to User Experience and Design oder Windows User Experience Interaction Guidelines Wie sieht die übliche Zusammenarbeit zwischen Designer und Entwicklern aus bei Desktopapplikationen und momentan noch verbreiteter im Web? Designer entwerfen coole Oberächen mit ihrem Lieblingstool auf ihrem Lieblingssystem, runde Ecken, Farbverläufe, Übergänge bei Aktionen,... sehr schön anzusehen. Entwickler uchen und möchten sich eigentlich auf die Funktionalität konzentrieren, stattdessen kämpfen sie Stunden, Wochen um die pixelgenaue Abbildung der in PNG o.ä. gelieferten Vorlagen. Kämpfe mit Vorgesetzten, ob man nicht hier und da Abstriche an der Vorlage machen kann. Aber gerade im Web, ist Präsentation wichtig, es soll in jedem Browser gleich aussehen. Gesucht ist also ein einheitliches Format, das leicht unter Entwicklern und Designern auszutauschen ist und den Anforderungen der Designer genügt. Einfach auszutauschendes Format schreit geradezu nach XML. Basierend auf XML gibt es Beschreibungssprachen für Oberächen. Ein ausführliche Übersicht nden Sie bei Wikipedia List of user interface markup languages. Microsoft wollte nicht nur eine mächtige Beschreibungssprache, die allen denkbaren Designeransprüchen genügt, sondern auch eine 1:1-Integration in ein OO-Modell, genauer gesagt, in ihr.net-oo-framework. Es wurde daher eine neue Beschreibungssprache deniert XAML und von Grund auf ein neues Framework aufgesetzt, das sich in.net integriert und alle XAML-Möglichkeiten in entsprechende Objekte und Eigenschaften abbildet. Eine Oberächenanwendung in WPF enthält also nicht mehr irgendwie generierten Code, den man nicht anfassen darf, sondern das Form (oder jedes andere visuelle Element) besteht 1 The Battle Between Usability and User-Experience 45

46 5.1 Architektur Abbildung 5.2: User Experience aus zwei oder mehr partiellen Klassendenitionen: XAML deniert das Aussehen und visuelle Verhalten deklarativ mit 1:1-Abbildung in das zugehörige Objektmodell und klassischer C#-Code bildet die Logik ab. 5.1 Architektur Abbildung 5.3: WPF Architektur 2 Das primäre WPF-Programmiermodell wird mithilfe von verwaltetem Code bereitgestellt. Am Anfang der Entwurfsphase von WPF gab es einige Diskussionen darüber, wo die Linie zwischen den im System verwalteten Komponenten und den nicht verwalteten gezogen werden sollte. Die CLR stellt eine Reihe von Features bereit, die zu einer produktiveren und robusteren Entwicklung führen (einschlieÿlich Speicherverwaltung, Fehlerbehandlung, allgemeines Typsystem usw.), die jedoch auch ihren Preis haben. PresentationFramework, PresentationCore und milcore stellen die Hauptbestandteile des Codes von WPF dar. Milcore ist in einem nicht verwalteten Code geschrieben, um eine enge Integration mit DirectX zu ermöglichen. Alle Anzeigen in WPF erfolgen durch das DirectX-Modul, um ein ezientes Hardware- und Softwarerendering zu gewährleisten. WPF erforderte auÿerdem eine Feinsteuerung des Speichers und der Ausführung. Das Erstellungsmodul in milcore ist äuÿerst leistungsabhängig und erforderte im Sinne der Leistungsverbesserung die Aufgabe vieler CLR-Vorteile. Sowohl WPF als auch Silverlight können XAML verarbeiten, also parsen und rendern (darstellen). Es gibt auch viele Designerwerkzeuge, die einen Export oder Import von XAML unterstützen. 2 WPF-Architektur 46 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

47 5.1 Architektur Abbildung 5.4: WPF wesentliche Klassen Die meisten WPF-Objekte werden aus DispatcherObject abgeleitet, in dem die grundlegenden Konstrukte zur Handhabung von Parallelität und Threading bereitgestellt werden. WPF basiert auf einem vom Verteiler implementierten Nachrichtensystem. Die Funktionsweise ist mit der bekannten Meldungsverteilschleife in Win32 zu vergleichen. Tatsächlich verwendet der WPF-Verteiler User32-Meldungen zum Ausführen von threadübergreifenden Aufrufen. WPF stellt ein umfangreicheres Eigenschaftensystem bereit, das vom DependencyObject-Typ abgeleitet wird. Das Eigenschaftensystem ist insofern wirklich ein Abhängigkeitseigenschaftensystem, als es die Abhängigkeiten zwischen den Eigenschaftsausdrücken erfasst und im Falle von Abhängigkeitsänderungen die Eigenschaftenwerte automatisch erneut überprüft. Wenn Sie z. B. eine Eigenschaft verwenden, die Werte erbt (z. B. FontSize), wird das System automatisch aktualisiert, wenn sich die Eigenschaft in einem übergeordneten Element des Elements ändert, das den Wert erbt. Anhand von Measure kann eine Komponente seine Gröÿe bestimmen. Hierbei handelt es sich um eine von Arrange getrennte Phase, da viele Situationen auftreten können, in denen ein übergeordnetes Element ein untergeordnetes Element auordert, mehrere Measures zur Ermittlung seiner optimalen Position und Gröÿe auszuführen. Die Tatsache, dass untergeordnete Elemente von übergeordneten Elementen zur Durchführung von Measures aufgefordert werden, verdeutlicht eine andere Schlüsselphilosophie von WPF Das Anpassen der Gröÿe an den Inhalt. Alle Steuerelemente in WPF unterstützen die Fähigkeit, sich an die natürliche Gröÿe ihres Inhalts anzupassen. Dies führt zu einer einfacheren Lokalisierung und ermöglicht aufgrund der Gröÿenanpassung ein dynamisches Elementlayout. Anhand der Arrange-Phase kann ein übergeordnetes Element jedes untergeordnete Element positionieren und dessen endgültige Gröÿe bestimmen. Jedes Eingabeereignis wird in mindestens zwei Ereignisse konvertiert in ein Vorschauereignis und in das tatsächliche Ereignis. Alle WPF-Ereignisse können innerhalb der Elementstruktur weitergeleitet werden. Ereignisse steigen in Blasen auf, wenn sie von einem Ziel entlang der Struktur nach oben bis zum Stamm traversieren. Sie arbeiten nach dem Tunnelprinzip, wenn sie vom Stamm ausgehend nach unten zu einem Ziel traversieren. Eingabenvorschauereignisse nutzen das Tunnelprinzip, wodurch jedes in der Struktur enthaltene Element das Ereignis ltern oder eine Ereignismaÿnahme ergreifen kann. Die regulären Ereignisse (keine Vorschauereignisse) steigen dann vom Ziel hoch zum Stamm auf. Diese Unterteilung zwischen der Tunnel- und Aufstiegsphase ermöglicht eine einheitliche Implementierung von Features (z. B. von Zugristasten) in einer gemischten Umgebung. In User32 würden Sie Zugristasten anhand einer einzelnen globalen Tabelle implementieren, die alle zu unterstützenden Zugristasten (Strg+N mit Neu verknüpft) enthält. In dem Verteiler Ihrer Anwendung würden Sie TranslateAccelerator aufrufen, der die Eingabemeldungen in User32 einliest und ermittelt, ob eine Übereinstimmung mit einer registrierten Zugristaste besteht. In WPF würde dies nicht funktionieren, da das System vollständig zusammensetzbar ist, d. h., jedes Element kann jede beliebige Zugristaste verarbeiten und verwenden. Dieses eingabenrelevante Zweiphasenmodell ermöglicht es Komponenten, den eigenen TranslateAccelerator zu implementieren. Darüber hinaus führt UIElement das Konzept der CommandBindings ein. Mithilfe des WPF-Befehlssystem können Entwickler Funktionalitäten in Form von Befehlsendpunkten denieren etwas, wodurch ICommand implementiert wird. Befehlsbindungen ermöglichen, dass Elemente die Zuordnung einer Eingabeaktion (Strg+N) 47 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

48 5.2 Ereignisse zu einem Befehl (Neu) denieren können. Sowohl Eingabeaktionen als auch Befehlsdenitionen sind erweiterbar und können zum Zeitpunkt der Verwendung miteinander verknüpft werden. Dadurch können Endbenutzer z. B. die in einer Anwendung zu verwendenden Tastenbindungen überaus einfach anpassen. 5.2 Ereignisse In XAML kann jeder Objekt andere Objekte enthalten. Ein Button, kann ein Image, einen Text und vielleicht eine TextBox zur Eingabe von Text enthalten. Wenn ich nun in die Textbox klicke, möchte ich den Text ändern können. Wie wird dieses Ereignis Klick in die Textbox verarbeitet? Wird gleichzeitig der Button geklickt und der Text geändert? Arbeiten Sie hierzu den Artikel auf Seite 29 im Anhang durch. Aufgabe 5.1 Erstellen Sie eine WPF-Anwendung mit einem Button, in dem eine TextBox und ein weiterer Button enthalten sind. Knüpfen Sie an die typischen Ereignisse eine Ausgabe. Debuggen Sie: Was passiert, welches Ereignis wird wo behandelt? Erstellen Sie zwei Styles für Ihre Applikation. Klick auf den äuÿeren Button vertauscht den aktuellen Style mit dem anderen Style. 5.3 WinForm und WPF Abbildung 5.5: WPF mit WinForm und umgekehrt (Quelle:Interoperabilität zwischen Windows Forms und WPF Soll ein auf WinForm basierendes bestehendes Produkt erweitert werden oder gibt es ein Control noch nicht für WPF, so können WPF und WinForm auch gut zusammen verwendet werden. Zur Integration von WPF in WinForm benötigen Sie die Assemblies WindowsFormsIntegration.dll, PresentationFramework.dll, PresentationCore.dll, WindowsBase.dll. Umgekehrt basiert der Zugri auf WinForm aus WPF heraus auf den Klassen WindowsFormsHost und ElementHost aus dem Namespace System.Windows.Forms.Integration. 48 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

49 6 Datenbankanbindung Die typischen Probleme datenbankbasierter Applikationen, wie gleichzeitiger lesender oder schreibender Zugri unter Berücksichtigung von Transaktionen oder die Unterstützung unterschiedlicher Datenbankmanagementsysteme bei sich veränderten Strukturen der beteiligten Tabellen, erfordern eine gute Unterstützung durch die Entwicklungsumgebung und Klassenbibliotheken. Handarbeit und umfangreiche individuelle Implementationen sind fehleranfällig und inezient. Die Abbildung der OO-Strukturen auf das relationale System erfolgt gerade bei gröÿeren Projekten über ORM (Objekt-Relational-Mapping). Dadurch können Änderungen an den Tabellen robust in die Applikation eingepegt werden. Dies übernimmt bei Microsoft das Entity Framework. Abbildung 6.1: DB: Technologien Abbildung 6.2: DB Technologien Die Basis von Datenbankzugrien in.net ist ADO.Net. ADO.Net bietet verschiedene Provider zum Zugri auf Datenbanken wie SQL Server, Oracle oder über OLE.Db und ODBC auf unterschiedliche Datenquellen. XML wird als Datenquelle zunehmend bedeutender, so dass auch hier ein performanter lesender, suchender und schreibender Zugri nötig ist. Über ADO.Net gibt es passende Interfaces, man muss jedoch für SQL Server und Oracle unterschiedliche Provider verwenden. Bisher musste man zur Unterstützung verschiedener Datenbankmanagementsysteme (DBMS) eine eigene Factory implementieren - dies wurde durch ein einheitliches Interface gut unterstützt, aber war eben händisch zu implementieren. Mit dem nun herausgegebenen Entity Framework soll dies entfallen ob dies auch für die grundunterschiedliche Handhabung von Triggern in Oracle und SQL Server zutrit, konnte ich noch nicht evaluieren. Mit LINQ steht eine zusätzliche, vom jeweiligen Datenbankmanagementsystem unabhängige Abfragesprache zur Verfügung, so dass auch Queries nicht für jedes System entsprechend formuliert werden müssen. Diese Unterschiede zwischen SQL Server und Oracle dies gilt natürlich auch für DB2, MySQL und andere DBMS können schon auf Select- oder Insert-Statements zutreen. Abhängig davon wie DBMS-spezisch man bisher ausgebildet ist, fällt einem mitunter gar nicht auf, dass man spezielle Features bei seiner Abfrage nutzt, die so in anderen DBMS nicht zur Verfügung stehen oder einer anderen Syntax bedarfen. Es gibt zwei Komponenten von ADO.NET, die Sie zum Zugreifen auf Daten und deren Bearbeitung verwenden können:.net Framework-Datenanbieter und das DataSet NET Framework-Datenanbieter Die.NET Framework-Datenanbieter sind Komponenten, die explizit für die Datenbearbeitung und den schnellen, vorwärts gerichteten, schreibgeschützten Zugri auf Daten entworfen wurden. Das Connection-Objekt sorgt für eine Verbindung mit einer Datenquelle. Mit dem Command-Objekt können Sie auf Datenbankbefehle zugreifen, um Daten zurückzugeben oder zu ändern, gespeicherte Prozeduren auszuführen und Parameterinformationen 49

50 6 Datenbankanbindung Abbildung 6.3: Verbindungsorientierter DB-Zugri zu senden oder abzurufen. Das DataReader-Objekt stellt einen Hochleistungsstream von Daten aus der Datenquelle zur Verfügung. Schlieÿlich fungiert der DataAdapter als Brücke zwischen dem DataSet-Objekt und der Datenquelle. Der DataAdapter verwendet Command-Objekte, zum Ausführen von SQL-Befehlen in der Datenquelle, um damit das DataSet mit Daten zu laden und Änderungen an den Daten im DataSet in die Datenquelle zu übernehmen. Der DataAdapter önet die Verbindung automatisch falls sie noch nicht oen ist und schlieÿt die Verbindung automatisch, falls diese selbst geönet wurde. Die wichtigsten Methoden des DataAdapters sind Fill() und Update(). Listing 6.1: Datenzugri mit DataReader string connstring = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;"; //mit using wird Connection und DataReader immer geschlossen! using (SqlConnection conn = new SqlConnection(connString)) SqlCommand cmd = conn.createcommand(); cmd.commandtext = "SELECT CustomerId, CompanyName FROM Customers"; conn.open(); using (SqlDataReader dr = cmd.executereader()) while (dr.read()) Console.WriteLine("0\t1", dr.getstring(0), dr.getstring(1)); SqlConnection nwindconn = new SqlConnection("Data Source=localhost; Integrated Security=SSPI;" + "Initial Catalog=northwind"); nwindconn.open(); SqlCommand catcmd = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories", nwindconn); SqlDataReader myreader = mycommand.executereader(); if (myreader.hasrows) while (myreader.read()) Console.WriteLine("\t0\t1", myreader.getint32(0), myreader.getstring(1)); else Console.WriteLine("No rows returned."); myreader.close(); //nur einen Wert auslesen: SqlCommand orderscmd = new SqlCommand("SELECT Count(*) FROM Orders", nwindconn); Int32 count = (Int32)ordersCMD.ExecuteScalar(); nwindconn.close(); //mit Parametern using (SqlConnection connection = new SqlConnection(connectionString)) SqlDataAdapter dataadpater = new SqlDataAdapter( 50 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

51 6 Datenbankanbindung "SELECT CategoryID, CategoryName FROM Categories", connection); dataadpater.updatecommand = new SqlCommand( "UPDATE Categories SET CategoryName " + "WHERE CategoryID connection); dataadpater.updatecommand.parameters.add( "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName"); SqlParameter parameter = dataadpater.updatecommand.parameters.add( "@CategoryID", SqlDbType.Int); parameter.sourcecolumn = "CategoryID"; parameter.sourceversion = DataRowVersion.Original; DataTable categorytable = new DataTable(); dataadpater.fill(categorytable); DataRow categoryrow = categorytable.rows[0]; categoryrow["categoryname"] = "New Beverages"; dataadpater.update(categorytable); Console.WriteLine("Rows after update."); foreach (DataRow row in categorytable.rows) Console.WriteLine("0: 1", row[0], row[1]); DataSet Abbildung 6.4: CTS in Relation zu CLS Das DataSet, ein aus einer Datenquelle abgerufener Datencache im Arbeitsspeicher, Das DataSet besteht aus einer Auistung von DataTable-Objekten, die Sie mit DataRelation-Objekten aufeinander beziehen können. In einer typischen Implementierung mit mehreren Ebenen werden die folgenden Schritte zum Erstellen und Aktualisieren eines DataSet und zum anschlieÿenden Aktualisieren der ursprünglichen Daten ausgeführt: 1 Das DataSet besteht aus einer Auistung von DataTable-Objekten, die Sie mit DataRelation-Objekten aufeinander beziehen können. 1. Erstellen Sie mithilfe eines DataAdapter jede DataTable in einem DataSet, und füllen Sie sie mit Daten aus einer Datenquelle. 1 DataSet-Klasse 51 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

52 6.1 Entity Framework 2. Ändern Sie die Daten in einzelnen DataTable-Objekten, indem Sie DataRow-Objekte hinzufügen, aktualisieren oder löschen. 3. Rufen Sie die GetChanges-Methode auf, um ein zweites DataSet zu erstellen, das nur die Änderungen an den Daten darstellt. 4. Rufen Sie die Update-Methode von DataAdapter auf, und übergeben Sie das zweite DataSet als Argument. 5. Rufen Sie die Merge-Methode auf, um die Änderungen aus dem zweiten DataSet mit dem ersten zusammenzuführen. 6. Rufen Sie AcceptChanges für das DataSet auf. Sie können auch RejectChanges aufrufen, um die Änderungen zu verwerfen. Listing 6.2: Update mit DataSet //connect to db SqlCommand myselectcommand = New SqlCommand("select * from customers", myconnection); SqlDataAdapter mysqldataadapter = new SqlDataAdapter(mySelectCommand); DataSet mydataset = new DataSet(); mysqldataadapter.fill(mydataset,"customers"); //anzeigen foreach (DataRow mydatarow in mydataset.tables["customers"].rows) Console.WriteLine(myDataRow["CustomerId"].ToString()); //löschen mydataset.tables["customers"].rows[0].delete(); //update mydataset.tables["customers"].rows[0]["contactname"]="peach"; mysqldataadapter.update(mydataset); DataSet oder DataReader Das ADO.NET-DataSet wurde explizit für den Datenzugri unabhängig von Datenquellen entworfen. Aus diesem Grund kann es mit mehreren, unterschiedlichen Datenquellen, mit XML-Daten oder zum Verwalten von lokalen Anwendungsdaten verwendet werden. Das DataSet enthält eine Auistung von einem oder mehreren DataTable-Objekten, die aus Datenzeilen und -spalten sowie aus Primärschlüsseln, Fremdschlüsseln, Einschränkungen und Beziehungsinformationen über die Daten in den DataTable-Objekten besteht. Wenn Sie sich zwischen einem DataReader oder einem DataSet für die Anwendung entscheiden möchten, müssen Sie den für die Anwendung erforderlichen Funktionalitätstyp berücksichtigen. Verwenden Sie für folgende Zwecke ein DataSet: Lokales Zwischenspeichern von Daten in Ihrer Anwendung, um sie bearbeiten zu können. Wenn Sie nur die Ergebnisse einer Abfrage anzeigen müssen, ist der DataReader die bessere Alternative. Verschieben von Daten zwischen Ebenen oder von einem XML-Webdienst. Dynamisches Interagieren mit Daten, wie Datenbindung an ein Windows Forms-Steuerelement, oder Kombinieren von und Erstellen einer Beziehung zwischen Daten aus mehreren Quellen. Ausführen umfangreicher Datenverarbeitungsschritte ohne eine oene Verbindung zur Datenquelle. Dadurch wird die Verbindung zur Nutzung durch andere Clients freigegeben. Wenn Sie die von DataSet bereitgestellten Funktionen nicht benötigen, können Sie die Leistung Ihrer Anwendung verbessern, indem Sie mithilfe des DataReader die Daten als schreibgeschützte Vorwärtsdaten zurückgeben. Obwohl der DataAdapter den DataReader zum Füllen des DataSet-Inhalts verwendet (siehe Auüllen eines DataSets mit einem DataAdapter-Objekt), können Sie die Leistung erhöhen, wenn Sie den DataReader verwenden. Dies ist möglich, weil Sie den Arbeitsspeicher, der für das DataSet erforderlich ist, nicht benötigen und die Verarbeitung, die zum Erstellen und Füllen des DataSet-Inhalts nötig ist, überüssig ist. 6.1 Entity Framework Entity Framework ist ein Satz von Technologien in ADO.NET, die die Entwicklung datenorientierter (relational) Softwareanwendungen (objektorient) unterstützen. 52 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

53 6.1 Entity Framework Mapping von Objekten zu Daten 2 Die objektorientierte Programmierung stellt eine Herausforderung für die Interaktion mit Datenspeichersystemen dar. Obwohl die Organisation der Klassen häug den Aufbau relationaler Datenbanktabellen recht genau widerspiegelt, passen diese Strukturen nicht perfekt zusammen. Oft entsprechen mehrere normalisierte Tabellen einer einzigen Klasse, und Beziehungen zwischen Klassen werden nicht auf dieselbe Weise dargestellt wie Beziehungen zwischen Tabellen. Um beispielsweise den Kunden für einen Auftrag darzustellen, verwendet die Order-Klasse eine Eigenschaft, die einen Verweis auf eine Instanz einer Customer-Klasse enthält. Eine Zeile in der Order-Tabelle in einer Datenbank enthält jedoch eine Fremdschlüsselspalte (oder mehrere Spalten als Fremdschlüssel) mit einem Wert, der einem Primärschlüsselwert in der Customer-Tabelle entspricht. Eine Customer-Klasse kann über eine Eigenschaft mit dem Namen Orders verfügen, die eine Auistung von Instanzen der Order-Klasse enthält. Die Customer-Tabelle in einer Datenbank verfügt jedoch nicht über eine vergleichbare Spalte. Vorhandene Lösungen haben versucht, diese Lücke, oft als Impedance Mismatch bezeichnet, zu füllen, indem nur objektorientierte Klassen und Eigenschaften relationalen Tabellen und Spalten zugeordnet wurden. Statt diesen herkömmlichen Ansatz zu verfolgen, ordnet Entity Framework relationale Tabellen, Spalten und Fremdschlüsseleinschränkungen in logischen Modellen den Entitäten und Beziehungen in konzeptionellen Modellen zu. Dadurch wird sowohl die Denition von Objekten als auch die Optimierung des logischen Modells viel exibler. Die Entitätsdatenmodell-Tools generieren erweiterbare Datenklassen auf der Grundlage des konzeptionellen Modells. Diese Klassen sind partielle Klassen, die mit zusätzlichen, vom Entwickler hinzuzufügenden Membern erweitert werden können. Die für ein bestimmtes konzeptionelles Modell erzeugten Klassen werden von Basisklassen abgeleitet, die Object Services zur Umsetzung von Entitäten in Objekte und zum Nachverfolgen und Speichern von Änderungen zur Verfügung stellen. Entwickler können diese Klassen verwenden, um die Entitäten und Beziehungen als Objekte zu behandeln, die durch Navigationseigenschaften verknüpft sind Zugreifen auf und Ändern von Entitätsdaten Entity Framework ist mehr als nur eine weitere objektrelationale Mappinglösung. Es dient im Wesentlichen dazu, Anwendungen den Zugri auf und die Änderung von Daten zu ermöglichen, die als Entitäten und Beziehungen im konzeptionellen Modell dargestellt werden. Object Services verwendet das EDM, um Objektabfragen von Entitätstypen, die im konzeptionellen Modell dargestellt werden, in datenquellenspezische Abfragen zu übersetzen. Abfrageergebnisse werden in Objekte umgesetzt, die von Object Services verwaltet werden. Entity Framework bietet die folgenden Möglichkeiten, ein EDM abzufragen und Objekte zurückzugeben: LINQ-to-Entities bietet Language Integrated Query (LINQ)-Unterstützung zum Abfragen von Entitätstypen, die in einem konzeptionellen Modell deniert sind. Entity SQL ein speicherunabhängiger SQL-Dialekt, der direkt mit Entitäten im konzeptionellen Modell arbeitet und EDM-Features, wie beispielsweise Vererbung und Beziehungen, unterstützt. Entity SQL wird sowohl für Objektabfragen als auch für Abfragen verwendet, die mithilfe des EntityClient-Anbieters ausgeführt werden. Abfrage-Generator-Methoden ermöglichen das Erstellen von Entity SQL-Abfragen unter Verwendung von Abfragemethoden im Stil von LINQ. Entity Framework enthält den EntityClient-Datenanbieter. Dieser Anbieter verwaltet Verbindungen, übersetzt Entitätsabfragen in datenquellenspezische Abfragen und gibt einen Datenleser zurück, mit dem Object Services Entitätsdaten in Objekte umsetzt. Wenn die Umsetzung in Objekte nicht erforderlich ist, kann der EntityClient- Anbieter auch wie ein ADO.NET-Standarddatenanbieter verwendet werden, indem er Anwendungen das Ausführen von Entity SQL-Abfragen und die Verarbeitung des zurückgegebenen schreibgeschützten Datenlesers ermöglicht. Entity Framework generiert eine von ObjectContext abgeleitete Klasse, die den im konzeptionellen Modell denierten Entitätencontainer darstellt. Dieser Objektkontext stellt die Funktionen zum Nachverfolgen von Änderungen und zum Verwalten von Identitäten, Parallelität und Beziehungen bereit. Diese Klasse macht auch eine SaveChanges-Methode verfügbar, die Einfügungen, Aktualisierungen und Löschungen in die Datenquelle schreibt. Diese Änderungen werden wie bei Abfragen entweder durch automatisch vom System generierte Befehle oder durch vom Entwickler angegebene gespeicherte Prozeduren vorgenommen. 2 Einführung in Entity Framework 53 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

54 6.2 LINQ Abbildung 6.5: Entity Framework Datenmodellierung im Entity Framework 3 Das Entitätsdatenmodell (EDM) ist ein Entitätsbeziehungsmodell. Mit dem EDM werden Daten in einem neutralen Format deniert, das nicht durch die Struktur von Programmiersprachen oder relationalen Datenbanken eingeschränkt ist. EDM-Schemas werden verwendet, um Details zu Entitäten und Beziehungen anzugeben und diese als Datenstrukturen zu implementieren. Eine Entität ist etwas in der Anwendungsdomäne, das durch Daten dargestellt werden muss. Beispiele für Entitäten und Beziehungen sind in einer typischen Geschäftsbereichsanwendung zu nden. Entitäten in der Domäne einer Geschäftsbereichsanwendung können Kunden, Aufträge, Auftragspositionen, Lieferanten, Produkte, Verkaufsmitarbeiter, Spediteure, Rechnungen usw. umfassen. Ein EDM-EntityType ist die Spezikation für einen Datentyp, der die Entität in der Anwendungsdomäne darstellt. Eine Beziehung ist die logische Verbindung zwischen Entitäten, wie beispielsweise zwischen einem Warenauftrag und dem Kunden, der den Auftrag aufgibt. Da ein Kunde über viele zugeordnete Aufträge verfügen kann, ist die Beziehung zwischen dem Kunden und seinen Aufträgen eine 1:n-Beziehung. Zwischen Produkten und Lieferanten kann eine m:n-beziehung bestehen. Das Denieren von Entitäten und Beziehungen kann ein sehr komplexer Vorgang sein. Etwas so Grundlegendes wie ein Warenauftrag in einer Geschäftsbereichsanwendung erfordert eine nicht zu unterschätzende Menge an Details. Zum Beispiel kann ein Warenauftrag unterschiedliche Formen haben. So könnte der Auftrag im Laden, am Telefon, im Internet oder per Katalog aufgegeben werden. Im EDM sind die Details der einzelnen Auftragstypen konzeptionell in XML-Syntax angegeben. Die Eigenschaften jedes Auftragstyps und notwendige Einschränkungen werden an Anwendungen weitergegeben, die Daten mit dem konzeptionellen Schema verwenden. Die Entitäten und ihre Beziehungen werden vom EDM mithilfe zweier grundlegender Typen modelliert. EntityType: Die abstrakte Spezikation für die Details einer Datenstruktur in der Anwendungsdomäne. AssociationType: Die logische Verbindung zwischen Typen. EDM-Generator (EdmGen.exe) ist ein Befehlszeilendienstprogramm, dass eine Verbindung zu einer Datenquelle herstellt und ein EDM auf der Grundlage eines 1:1-Mappings zwischen Entitäten und Tabellen erstellt. Auÿerdem verwendet es eine Konzeptmodelldatei (.csdl), um eine Objektebenendatei mit Klassen zu erzeugen, die Entitätstypen und den ObjectContext darstellen. 6.2 LINQ Mit LINQ (Language Integrated Query) gibt es eine Abfragesprache, die sowohl für Listen als auch als Datenbankabfragesprache oder zur Abfrage von XML-Dateien verwendet werden kann. Dabei ist die Sprache direkt in C# integriert, es müssen also nicht irgendwelche Strings zur Abfrage zusammengesetzt werden. 3 Datenmodellierung im Entity Framework 54 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

55 6.2 LINQ Abbildung 6.6: LINQ 4 Im Gegensatz zu z.b. SQL wird die Abfrage nicht als String übergeben, sondern ist nativ in den Quellcode integriert. Das bietet z.b. den Vorteil, dass der.net-sprachcompiler die Abfrage direkt auf Syntaxfehler prüfen kann, um spätere Laufzeitfehler zu vermeiden. Die Syntax von LINQ erinnert sehr an die SQL-Abfragesprache mit Befehlen wie z.b. select, from, where und orderby. LINQ ndet im Wesentlichen die folgenden vier Anwendungsgebiete: LINQ-to-Dataset: bietet Abfragemöglichkeiten für Objekte, die in einem DataSet-Objekt gespeichert sind. LINQ-to-SQL (DLINQ): übersetzt die native LINQ-Abfrage in SQL und sendet diese an eine relationale Datenbank. Von der Datenbank gelieferte Ergebnisse werden dann entsprechend wieder in ein Objektmodell übersetzt. LINQ-to-XML (XLINQ): bietet Zugri auf XML-Dokumente (DOM-Manipulation) LINQ-to-Objects: bietet Abfragemöglichkeiten für.net-objektmengen, die in Listen gespeichert sind, z.b. in List, Array oder Dictionary (müssen das Interface IEnumerable bzw. IEnumerable<T> implementieren. Die wesentlichen LINQ-Klassen werden in den Namensräumen System.Linq.*, System.Data.Linq sowie System.Xml.Linq zur Verfügung gestellt. Darüber hinaus gibt es zahlreiche LINQ-Projekte anderer Hersteller und Anbieter, um nur einige der zahlreichen Beispiele zu nennen: LINQ-to-MySQL, LINQ-to-LDAP, LINQ-to-Flickr, LINQ-to-Amazon,... int[] numbers = 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ; var lownums = from n in numbers where n < 5 select n; List<Product> products = GetProductList(); var soldoutproducts = from p in products where p.unitsinstock == 0 select p; string[] words = "apple", "BlUeBeRrY", "cherry" ; Listing 6.3: LINQ-Beispiele var upperlowerwords = from w in words select new Upper = w.toupper(), Lower = w.tolower() ; 4.Net Glossar 55 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

56 6.3 Datenbindung 6.3 Datenbindung Der Begri Datenbindung beschäftigt sich mit der Problematik Änderungen an den Daten einer Datenquelle in Steuerelementen eines Formulars anzuzeigen und vorzunehmen. Die Datenbindung ist grundsätzlich ein automatisches Verfahren, um für beliebige Steuerelemente im Formular Eigenschaften festzulegen, auf die zur Laufzeit zugegrien werden kann. 5 Die Änderungsbenachrichtigung ist einer der wichtigsten Bestandteile der Windows Forms-Datenbindung. Um sicherzustellen, dass die Datenquelle und die gebundenen Steuerelemente immer über aktuelle Daten verfügen, müssen Sie die Änderungsbenachrichtigung für die Datenbindung hinzufügen. Der Hauptzweck liegt darin, dass gebundene Steuerelemente über Änderungen an der zugehörigen Datenquelle benachrichtigt werden und die Datenquelle über Änderungen benachrichtigt wird, die an den gebundenen Eigenschaften eines Steuerelements vorgenommen wurden Datenbindung in WinForm 6 Herkömmlicherweise wurde die Datenbindung in Anwendungen verwendet, um in Datenbanken gespeicherte Daten nutzen zu können. Mit der Datenbindung von Windows Forms können Sie auf Daten zugreifen, die in Datenbanken sowie in anderen Strukturen, z. B. Arrays oder Auistungen, enthalten sind. Die folgende Liste enthält die Strukturen, an die Sie in Windows Forms eine Bindung vornehmen können. BindingSource ist die häugste Windows Forms-Datenquelle. Sie fungiert als Proxy zwischen einer Datenquelle und Windows Forms-Steuerelementen. Das allgemeine Verwendungsmuster von BindingSource sieht vor, Steuerelemente an BindingSource und BindingSource an die Datenquelle (z. B. eine ADO.NET- Datenquelle oder ein Geschäftsobjekt) zu binden. Windows Forms unterstützt in Objektinstanzen mithilfe des Binding-Typs die Datenbindung von Steuerelementeigenschaften an öentliche Eigenschaften. Auÿerdem unterstützt Windows Forms die Bindung listenbasierter Steuerelemente, z. B. ListControl, an eine Objektinstanz, wenn BindingSource verwendet wird. Damit eine Liste als Datenquelle verwendet werden kann, muss sie die IList-Schnittstelle implementieren. ADO.NET: DataColumn ist der wichtigste Baustein von DataTable, da eine Tabelle sich aus einer Reihe von Spalten zusammensetzt. Jedes DataColumn-Objekt verfügt über eine DataType-Eigenschaft, die die Art der Daten bestimmt, die in der Spalte enthalten sind (in einer Tabelle zur Beschreibung von Autos z. B. die Marke der Autos). Ein Steuerelement (bei einem TextBox-Steuerelement z. B. die Text-Eigenschaft) kann mithilfe der einfachen Bindung an eine Spalte in einer Datentabelle gebunden werden. DataTable ist die Darstellung einer Tabelle mit Zeilen und Spalten, wie sie in ADO.NET verwendet wird. Eine Datentabelle umfasst zwei Auistungen: DataColumn für die Datenspalten in einer bestimmten Tabelle (dadurch wird letztlich bestimmt, welche Arten von Daten in diese Tabelle eingegeben werden können) sowie DataRow für die Datenzeilen in einer bestimmten Tabelle. Ein Steuerelement kann mithilfe der komplexen Bindung an die Daten in einer Datentabelle gebunden werden (beispielsweise bei Bindung des DataGridView-Steuerelements an eine Datentabelle). Bei der Bindung an DataTable erstellen Sie tatsächlich eine Bindung an die Standardansicht dieser Tabelle. DataView ist eine angepasste Ansicht einer einzelnen Datentabelle, die geltert oder sortiert werden kann. Eine Datenansicht ist eine Momentaufnahme der Daten, die von komplex gebundenen Steuerelementen verwendet werden. Für die Daten in einer Datenansicht können Sie einfache oder komplexe Bindungen vornehmen. Dabei sollten Sie jedoch beachten, dass Sie nicht Bindungen an eine saubere, aktualisierende Datenquelle, sondern an ein festes Abbild der Daten vornehmen. DataSet ist eine Auistung von Tabellen, Beziehungen und Einschränkungen der Daten in einer Datenbank. Sie können Daten innerhalb eines DataSets mithilfe der einfachen oder komplexen Bindung binden. Stellen Sie jedoch sicher, dass Sie an den standardmäÿigen DataViewManager für DataSet binden (siehe dazu den nächsten Gliederungspunkt). 5 Änderungsbenachrichtigung in der Windows Forms-Datenbindung 6 Von Windows Forms unterstützte Datenquellen 56 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

57 6.3 Datenbindung DataViewManager ist eine angepasste Ansicht des gesamten DataSet. Sie entspricht grundsätzlich DataView, enthält aber zusätzlich Beziehungen. Mit einer DataViewSettings-Auistung können Sie standardmäÿige Filter- und Sortieroptionen für beliebige Ansichten festlegen, die DataViewManager für eine bestimmte Tabelle bereitstellt. Die Bindung eines Datagrids DataGrid1 an eine Tabelle Customers eines Datasets dscustomers ist nun nur noch ein Einzeiler: DataGrid1.SetDataBinding(dsCustomers, "Customers"); Listing 6.4: Datenbindung an ein DataGrid Datenbindung in WPF 7 Elemente können an Daten aus einer Vielzahl von Datenquellen in Form von common language runtime (CLR)- Objekten und XML gebunden werden. ContentControl wie Button und ItemsControl wie ListBox und ListView verfügen über integrierte Funktionen, die eine exible Formatierung von einzelnen Datenelementen oder Auflistungen von Datenelementen ermöglichen. Sortier-, Filter- und Gruppenansichten können übergreifend für die Daten generiert werden. Unabhängig davon, was für ein Element Sie binden und welcher Art die Datenquelle ist, geschieht die Bindung immer nach dem in Abbildung 6.7 gezeigten Modell: Abbildung 6.7: Datenbindung in WPF Wie in der Abbildung dargestellt, ist Datenbindung die Brücke zwischen dem Bindungsziel und der Bindungsquelle. Eine Bindung besteht in der Regel aus diesen vier Komponenten: einem Bindungszielobjekt, einer Zieleigenschaft, einer Bindungsquelle sowie einem Pfad zum Wert in der Bindungsquelle, die verwendet werden soll. Angenommen, Sie möchten den Inhalt von TextBox an die Name-Eigenschaft eines Employee-Objekts binden, dann ist Ihr Zielobjekt TextBox, die Zieleigenschaft die Text-Eigenschaft, der zu verwendende Wert Name und das Quellobjekt das Employee-Objekt. Über die Mode-Eigenschaft des Binding-Objekts können Sie festlegen, ob und wie Änderungen festgeschrieben werden. Abbildung 6.8: Datenbindungsuss OneWay-Bindung bewirkt, dass bei Änderungen an der Quelleigenschaft die Zieleigenschaft automatisch aktualisiert wird, ohne dass Änderungen an der Zieleigenschaft an die Quelleigenschaft zurückübertragen werden. TwoWay-Bindung bewirkt, dass bei Änderungen an der Quelleigenschaft bzw. der Zieleigenschaft die jeweils andere automatisch aktualisiert wird. OneWayToSource stellt die Umkehrung der OneWay-Bindung dar: die Quelleigenschaft wird aktualisiert, wenn sich die Zieleigenschaft ändert. Folgendes Beispiel zeigt, wie ein Windows Presentation Foundation (WPF)ListBox-Steuerelement an ein ADO.NETDataSet gebunden wird. 7 Übersicht über Datenbindung 57 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

58 6.4 Aufgaben DataSet mydataset; Listing 6.5: Datenbindung in WPF private void OnInit(object sender, EventArgs e) //Verbindung herstellen... OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM BookTable;", conn); mydataset = new DataSet(); adapter.fill(mydataset, "BookTable"); mylistbox.datacontext = mydataset;... XAML: <ListBox Name="myListBox" Height="200" ItemsSource="Binding Path=BookTable" ItemTemplate ="StaticResource BookItemTemplate"/> <StackPanel.Resources> <c:intcolorconverter x:key="myconverter"/> <DataTemplate x:key="bookitemtemplate"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="250" /> <ColumnDefinition Width="100" /> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="Binding Path=Title" Grid.Column="0" FontWeight="Bold" /> <TextBlock Text="Binding Path=ISBN" Grid.Column="1" /> <TextBlock Grid.Column="2" Text="Binding Path=NumPages" Background="Binding Path=NumPages, Converter=StaticResource MyConverter"/> </Grid> </DataTemplate> </StackPanel.Resources> Datenbindung in Asp.Net Die serverseitige Datenbindung in WebForms erfolgt analog zu WinForm: Collection<StockInfo> stocks = GetLatestQuotes(...); DataGrid1.DataSource = stocks; DataGrid1.DataBind(); Listing 6.6: Serverseitige Datenbindung in Asp.Net Mit AJAX gibt es auch die Möglichkeit einer clientseitigen Datenbindung. 6.4 Aufgaben Die Aufgaben stammen von.net AT JKU. Aufgabe 6.1 Zugrisart bei gleichzeitigem Zugri. In einer Anwendung möchten viele Benutzer gleichzeitig die Daten einer Tabelle (z.b. Produkte) lesen. Verwenden Sie eher einen verbindungsorientierten oder einen verbindungslosen Zugri? Aufgabe 6.2 Ändern von Daten. Werden die Änderungen der Daten bei einem verbindungslosen Zugri auch in der Datenbank automatisch durchgeführt? Falls ja, wodurch, falls nein, wie können sie trotzdem durchgeführt Aufgabe 6.3 Schreiben Sie ein Kommandozeilenprogramm ExportXML, welches alle Daten und Tabellen einer Datenbank ausliest und in einer XML-Datei abspeichert. Der erste Kommandozeilenparameter ist der Name der Verbindung und der zweite Paramter gibt den Namen der zu erzeugenden XML-Datei an. Die exportierte XML- Datei soll auch das Schema der Datenbank enthalten. 58 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

59 7 Webentwicklung Abbildung 7.1: Asp.Net Überblick Aus den ursprünglichen skriptbasierten ASP-Seiten, die ähnlich wie frühere PHP-Seiten aussahen, häug sogar mit VB-Skript nur browserspezisch arbeiteten, ist mittlerweile eine gute Entwicklungsmöglichkeit fürs Web entwachsen. Selbst die erste Version von Asp.Net war schon mächtig. Man gestaltet seine Webseiten wie bei WinForm durch Drag&Drop vorhandener Steuerelemente, kann eigene Komponenten implementieren und über CodeBehind programmiert man die zugehörigen PostBacks. Prinzipiell wird immer an die gleiche Seite zurückgeschickt. Das Konzept bei Asp.Net ist ähnlich zu WinForm: ereignisorientiert. Über Server.Transfer kann man zu einer anderen Seite navigieren. Die Steuerelemente ermöglichen einen einfachen Anschluss an Datenstrukturen und Datenbanken und hinter der Oberäche arbeitet man mit C# wie gewohnt objektorientiert. In der ersten Version von Asp.Net waren die Seiten noch nicht barrierefrei und ein einheitliches Look&Feel war nur umständlich selbst zu programmieren. Durch die Einführung von sogenannten Masterpages und eine bessere HTML-Codeerzeugung sind diese beiden Probleme gut gelöst. Die aktuelle Version setzt auf JSON und unterstützt nun auch die Entwicklung von AJAX-basierten Seiten gut. Asp.Net implementiert nicht das MVC- Pattern, Modell und Controller sind typischerweise miteinander vermischt. Für gröÿere Applikationen ist MVC jedoch aktuell State of the Art, so dass mit.net 4.0 nun auch eine Klassenbibliothek hierfür existiert, die auf Asp.Net aufsetzt. 59

60 7.1 Asp.Net 7.1 Asp.Net Das ASP.NET-Framework für Seiten und Steuerelemente ist ein Programmierframework, das auf einem Webserver ausgeführt wird, um ASP.NET-Webseiten dynamisch zu erstellen und zu rendern. ASP.NET-Webseiten können von jedem Browser oder Clientgerät angefordert werden, und ASP.NET rendert Markup (wie HTML) für den anfordernden Browser. Grundsätzlich kann dieselbe Seite für mehrere Browser verwenden werden, da ASP.NET das Markup dem anfordernden Browser entsprechend rendert. ASP.NET unterstützt mobile Steuerelemente für webkompatible Geräte, wie Handys, Taschencomputer und persönliche digitale Assistenten (PDAs, Personal Digital Assistants). ASP.NET-Webseiten sind vollkommen objektorientiert. Innerhalb von ASP.NET- Webseiten können Sie für die Arbeit mit HTML-Elementen Eigenschaften, Methoden und Ereignisse verwenden. Das ASP.NET-Seitengerüst entfernt die Implementierungsdetails der Trennung von Client und Server, die den webbasierten Anwendungen eigen ist, indem ein vereinheitlichtes Modell für das Reagieren auf Clientereignisse im Code verwendet wird, das auf dem Server ausgeführt wird. Das Gerüst verwaltet während des Lebenszyklus der Seitenverarbeitung auch automatisch den Status einer Seite und der Steuerelemente auf der Seite. Das ASP.NET-Framework für Seiten und Steuerelemente bietet durch verschiedene Designs die Möglichkeit, das Gesamterscheinungsbild und Verhalten einer Website zu steuern. Sie können Designs und Skins denieren und dann auf Seitenebene oder Steuerelementebene anwenden Masterseiten Neben Designs können Sie auch Masterseiten denieren, um ein konsistentes Layout der Anwendungsseiten zu erstellen. In einer Masterseite werden das Layout und das Standardverhalten aller Seiten (oder einer Gruppe von Seiten) der Anwendung festgelegt. Sie können anschlieÿend einzelne Inhaltsseiten erstellen, die den spezischen Inhalt für die darzustellende Seite enthalten. Beim Anfordern einer Inhaltsseite durch den Benutzer werden Inhaltsseite und Masterseite zusammengeführt. Das Ergebnis ist eine Kombination aus dem Inhalt der Inhaltsseite und dem Layout der Masterseite. Mit ASP.NET-Masterseiten können Sie ein Seitenlayout erstellen (eine Masterseite), das Sie mit ausgewählten oder allen Seiten (Inhaltsseiten) in der Website verwenden können. Masterseiten können ein nützliches Hilfsmittel beim Erstellen eines einheitlichen Erscheinungsbilds einer Site sein. Die Themen in diesem Abschnitt führen in Masterseiten ein und beschreiben, wie diese erstellt und verwaltet werden Lebenszyklus einer Seite Im Allgemeinen durchläuft eine Asp.Net-Seite die folgenden Phasen: Seitenanforderung: Der Lebenszyklus einer Seite beginnt, nachdem die Seite angefordert wurde. Wenn ein Benutzer die Seite anfordert, prüft ASP.NET, ob die Seite analysiert und kompiliert werden muss (Beginn des Lebenszyklus einer Seite) oder ob eine zwischengespeicherte Version der Seite zurückgesendet werden kann, ohne dass die Seite verarbeitet werden muss. Starten: In der Startphase werden Seiteneigenschaften wie Request und Response festgelegt. In dieser Phase wird auch bestimmt, ob es sich bei der Anforderung um ein Postback oder um eine neue Anforderung handelt, und die IsPostBack-Eigenschaft wird entsprechend festgelegt. Auÿerdem wird in der Startphase die UICulture-Eigenschaft festgelegt. Seiteninitialisierung: Während der Seiteninitialisierung sind die Steuerelemente auf der Seite verfügbar, und die UniqueID-Eigenschaft jedes Steuerelements wird festgelegt. Ebenso werden gegebenenfalls Designs für die Seite übernommen. Wenn es sich bei der aktuellen Anforderung um ein Postback handelt, sind die Postbackdaten noch nicht geladen, und die Eigenschaftenwerte des Steuerelements wurden noch nicht mit den Werten aus dem Ansichtszustand wiederhergestellt. Laden:Wenn es sich bei der aktuellen Anforderung um ein Postback handelt, werden die Steuerelementeigenschaften während der Ladephase mithilfe von Informationen aus dem Ansichtszustand und dem Steuerelementzustand wiederhergestellt. Validierung: Während der Validierung wird die Validate-Methode aller Validierungssteuerelemente aufgerufen, die die IsValid-Eigenschaft einzelner Validierungssteuerelemente sowie der Seite festlegt. Behandlung von Postbackereignissen: Wenn es sich bei der Anforderung um ein Postback handelt, werden sämtliche Ereignishandler aufgerufen. 60 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

61 7.1 Asp.Net Rendern: Vor der Darstellung werden der Ansichtszustand für die Seite sowie alle Steuerelemente gespeichert. Während der Wiedergabephase wird von der Seite die Render-Methode für jedes Steuerelement aufgerufen. Dadurch wird ein Textschreiber bereitgestellt, der eine Ausgabe in OutputStream der Response-Eigenschaft der Seite schreibt. Entladen: Nachdem die Seite vollständig dargestellt und an den Client gesendet wurde und daher verworfen werden kann, wird der Entladevorgang aufgerufen. An dieser Stelle werden Seiteneigenschaften wie Response und Request entladen, und es werden sämtliche Bereinigungsoperationen ausgeführt Ereignismodell für ASP.NET-Webserversteuerelemente Ein wichtiges Feature von ASP.NET ist die Möglichkeit, Webseiten mit einem ereignisbasierten Modell zu programmieren, wie es auch für Clientanwendungen verwendet wird. Ein einfaches Beispiel: Sie fügen einer ASP.NET-Webseite eine Schaltäche hinzu und schreiben anschlieÿend einen Ereignishandler für das Klickereignis der Schaltäche. Dieses Vorgehen kennen wir zwar schon von Webseiten her, die ausschlieÿlich mit Clientskript arbeiten (wobei das onclick-ereignis mit dynamischem HTML behandelt wird). ASP.NET überträgt dieses Modell jedoch auf die serverbasierte Verarbeitung. Durch ASP.NET-Serversteuerelemente ausgelöste Ereignisse unterscheiden sich geringfügig von Ereignissen in herkömmlichen HTML-Seiten oder clientbasierten Webanwendungen. Der Unterschied entsteht hauptsächlich durch die Trennung des Ereignisses selbst von der Stelle, wo das Ereignis behandelt wird. In clientbasierten Anwendungen werden Ereignisse auf dem Client ausgelöst und behandelt. In ASP.NET-Webseiten haben Ereignisse, die Serversteuerelementen zugeordnet sind, ihren Ursprung auf dem Client (Browser). Sie werden jedoch von der ASP.NET-Seite auf dem Webserver behandelt. Für auf dem Client ausgelöste Ereignisse benötigt das Ereignismodell für ASP.NET-Websteuerelemente auf dem Client erfasste Ereignisinformationen sowie eine Ereignismeldung, die über HTTP Post an den Server übertragen wird. Die Seite muss die Meldung interpretieren, um festzustellen, welches Ereignis aufgetreten ist, und muss dann die entsprechende Methode im Code auf dem Server aufrufen, um das Ereignis zu behandeln. ASP.NET behandelt alle Aufgaben, die beim Erfassen, Senden und Interpretieren des Ereignisses durchgeführt werden. Beim Erstellen von Ereignishandlern in einer ASP.NET-Webseite müssen Sie sich normalerweise nicht darum kümmern, wie die Ereignisinformationen erfasst und dem Code zur Verfügung gestellt werden. Stattdessen können Sie Ereignishandler wie in einem herkömmlichen Clientformular erstellen. Allerdings gibt es einige Aspekte bei der Ereignisbehandlung in ASP.NET-Webseiten, die Sie beachten sollten. Ereignissatz für Serversteuerelemente und Seiten Serversteuerelementereignisse und PostBack: Da die meisten ASP.NET-Serversteuerelementereignisse zur Verarbeitung einen Roundtrip zum Server erfordern, können sie die Leistung der Seite beeinträchtigen. Daher bieten Serversteuerelemente einen eingeschränkten Satz an Ereignissen, die normalerweise auf Klickereignisse beschränkt sind. Einige Serversteuerelemente unterstützen Änderungsereignisse. Zum Beispiel löst das CheckBox-Webserversteuerelement im Servercode ein CheckedChanged-Ereignis aus, wenn der Benutzer auf das Kontrollkästchen klickt. Einige Serversteuerelemente unterstützen abstraktere Ereignisse. Das Calendar- Webserversteuerelement z. B. löst ein SelectionChanged-Ereignis aus, das eine abstraktere Version des Klickereignisses ist. Ereignisse, die häug auftreten (und ohne das Wissen des Benutzers ausgelöst werden können), wie das onmouseover-ereignis, werden von Serversteuerelementen nicht unterstützt. ASP.NET-Serversteuerelemente können für solche Ereignisse aber clientseitige Handler aufrufen. Dies wird weiter unten unter Ereignismodell für ASP.NET-Webserversteuerelemente erklärt. Steuerelemente und die Seite selbst lösen bei jedem Verarbeitungsschritt ebenfalls Lebenszyklusereignisse aus, z. B. Init, Load und PreRender. Sie können diese Lebenszyklusereignisse in der Anwendung nutzen. Sie können zum Beispiel im Load-Ereignis einer Seite Standardwerte für Steuerelemente festlegen. Ereignisargumente Serverbasierte Ereignisse von ASP.NET-Seiten und -Steuerelementen folgen einem.net Framework-Standardmuster für Ereignishandlermethoden. Alle Ereignisse übergeben zwei Argumente: ein Objekt, das das Ereignis auslösende Objekt darstellt, und ein Ereignisobjekt, das ereignisspezische Informationen enthält. Das zweite Argument ist normalerweise vom Typ EventArgs, aber bei manchen Steuerelementen ist es von einem Typ, der für dieses Steuerelement spezisch ist. Für ein ImageButton- Webserversteuerelement ist z. B. das zweite Argument vom Typ ImageClickEventArgs. Es enthält Informationen über die Koordinaten des Punkts, auf den der Benutzer geklickt hat. Ereignisse für Seiten (beispielsweise das Load-Ereignis der Seite) akzeptieren die beiden Standardargumente, in denen dann allerdings keine Werte übergeben werden. Postbackereignisse und Nicht-Postbackereignisse in Serversteuerelementen In Serversteuerelementen führen bestimmte Ereignisse (normalerweise Klickereignisse) dazu, dass die Seite unmittelbar an den Server zurückgesendet wird. Änderungsereignisse in HTML-Serversteuerelementen und Webserversteuerelementen, wie das TextBox-Steuerelement, verursachen kein sofortiges Postback. Stattdessen werden sie bei 61 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

62 7.1 Asp.Net dem nächsten Postback ausgelöst. Falls dies vom Browser unterstützt wird, können Validierungssteuerelemente Benutzereingaben mit Clientskript prüfen ohne einen Roundtrip zum Server. Ausführliche Informationen nden Sie unter Überprüfen der Benutzereingabe in ASP.NET-Webseiten. Nach dem Zurücksenden der Seite werden die Initialisierungsereignisse der Seite (Page_Init und Page_Load) ausgelöst, und anschlieÿend werden Steuerelementereignisse verarbeitet. Sie sollten keine Anwendungslogik erstellen, die von in einer bestimmten Reihenfolge ausgelösten Änderungsereignissen abhängt, es sei denn, Sie verfügen über fundierte Kenntnisse der Seitenereignisverarbeitung. Ausführliche Informationen nden Sie unter Übersicht über den Lebenszyklus von ASP.NET-Seiten. Falls es für Ihre Anwendung sinnvoll ist, können Sie angeben, dass Änderungsereignisse einen Postback der Seite auslösen. Webserversteuerelemente, die ein Änderungsereignis unterstützen, enthalten eine AutoPostBack-Eigenschaft. Wenn diese Eigenschaft auf true festgelegt wurde, löst das Änderungsereignis des Steuerelements sofort ein Postback der Seite aus, ohne dass auf ein Klickereignis gewartet wird. Das CheckedChanged-Ereignis eines CheckBox-Steuerelements löst z. B. standardmäÿig keine Übermittlung der Seite aus. Wenn Sie aber die AutoPostBack-Eigenschaft des Steuerelements auf true festlegen, wird die Seite zur Verarbeitung an den Server gesendet, sobald ein Benutzer auf das Kontrollkästchen klickt. Damit die AutoPostBack- Eigenschaft ordnungsgemäÿ funktioniert, muss der Browser des Benutzers Skripts zulassen. Meistens ist das die Standardeinstellung. Allerdings deaktivieren manche Benutzer Skripts aus Sicherheitsgründen. Ausführliche Informationen nden Sie unter Clientskript in ASP.NET-Webseiten. Weitergeleitete Ereignisse: Zusätzlich zu Seiten- und Steuerelementereignissen bietet ASP.NET Möglichkeiten zum Arbeiten mit Lebenszyklusereignissen, die ausgelöst werden, wenn die Anwendung gestartet oder beendet wird (Anwendungsereignisse) oder wenn die Sitzung eines einzelnen Benutzers gestartet oder beendet wird (Sitzungsereignisse): Anwendungsereignisse werden für alle Anforderungen einer Anwendung ausgelöst. Zum Beispiel wird das BeginRequest-Ereignis des HttpApplication-Objekts (Application/_BeginRequest) ausgelöst, wenn eine ASP.NET-Webseite oder ein XML-Webdienst in der Anwendung angefordert wird. Mit diesem Ereignis können Sie Ressourcen initialisieren, die für die Anforderungen an die Anwendung verwendet werden. Ein entsprechendes Ereignis, das EndRequest-Ereignis des HttpApplication-Objekts (Application/_EndRequest), gibt Ihnen die Möglichkeit, für die Anforderung verwendete Ressourcen zu schlieÿen oder freizugeben. Sitzungsereignisse ähneln Anwendungsereignissen (es gibt ein Start-Ereignis und ein End-Ereignis). Sie werden jedoch für jede einzelne Sitzung innerhalb der Anwendung ausgelöst. Eine Sitzung beginnt, wenn ein Benutzer eine Seite zum ersten Mal von der Anwendung anfordert, und endet, wenn die Anwendung die Sitzung explizit schlieÿt oder wenn die Sitzung das Zeitlimit überschreitet. Das Session_End-Ereignis wird nicht unter allen Umständen ausgelöst Zustandsverwaltung Bei jeder Bereitstellung einer Webseite auf dem Server wird eine neue Instanz der Webseitenklasse erstellt. Bei der herkömmlichen Webprogrammierung würde dies normalerweise bedeuten, dass alle zur Seite gehörenden Informationen und die Steuerelemente auf der Seite bei jeder Client-Server-Schleife (Roundtrip) verloren gingen. Wenn z. B. ein Benutzer Informationen in ein Textfeld eingibt, würden diese Informationen während der Schleife vom Browser oder Clientgerät zum Server verloren gehen. Um diese inhärente Einschränkung der herkömmlichen Webprogrammierung zu überwinden, enthält ASP.NET eine Reihe von Optionen, mit denen Sie die Daten sowohl auf Seitenbasis als auch auf Anwendungsbasis bewahren können. Es handelt sich um folgende Features: Ansichtszustand, Steuerelementzustand, Ausgeblendete Felder, Cookies, Abfragezeichenfolgen, Anwendungszustand, Sitzungszustand, Proleigenschaften. Ansichtszustand, Steuerelementzustand, ausgeblendete Felder, Cookies und Abfragezeichenfolgen speichern die Daten jeweils auf dem Client. Anwendungszustand, Sitzungszustand und Proleigenschaften hingegen speichern die Daten im Speicher des Servers. Jede Option hat je nach Einsatzszenario unterschiedliche Vor- und Nachteile. In den folgenden Abschnitten werden Optionen für die Zustandsverwaltung beschrieben, für die das Speichern der Informationen entweder in der Seite oder auf dem Client erforderlich ist. Bei diesen Optionen bleiben die Informationen auf dem Server zwischen den Schleifen nicht erhalten. Ansichtszustand:Die ViewState-Eigenschaft enthält ein Dictionary-Objekt, um Werte zwischen mehreren Anforderungen derselben Seite beizubehalten. Dies ist die Standardmethode, die die Seite zum Beibehalten von Seitenwerten und Werten für Steuerelementeigenschaften zwischen den Schleifen verwendet. Bei der Verarbeitung der Seite wird der aktuelle Status der Seite und der Steuerelemente in eine Zeichenfolge gehasht und in der Seite als ausgeblendetes Feld gespeichert. Wenn die in der ViewState-Eigenschaft gespeicherte Datenmenge 62 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

63 7.1 Asp.Net den in der MaxPageStateFieldLength-Eigenschaft angegebenen Wert übersteigt, werden zur Speicherung mehrere ausgeblendete Felder verwendet. Beim Zurücksenden der Seite an den Server wird die Zeichenfolge für den Ansichtszustand bei der Seiteninitialisierung analysiert, und die Eigenschafteninformationen in der Seite werden wiederhergestellt. Die Möglichkeiten von Cookies und URLs stehen Ihnen in Asp.Net auch zur Verfügung. ASP.NET bietet Ihnen vielfältige Möglichkeiten zum Verwalten von Zustandsinformationen auf dem Server, sodass die Informationen nicht für längere Zeit auf dem Client gespeichert werden müssen. Mit der serverbasierten Zustandsverwaltung können Sie die Informationsmenge verringern, die zur Beibehaltung des Zustands an den Client gesendet wird. Dabei werden jedoch kostbare Ressourcen auf dem Server verbraucht. In den folgenden Abschnitten werden drei Features für die serverbasierte Zustandsverwaltung beschrieben: Anwendungszustand, Sitzungszustand und Proleigenschaften. Anwendungszustand: In ASP.NET können Sie mithilfe des Anwendungszustands, der eine Instanz der HttpApplicationState-Klasse ist, Werte für jede aktive Webanwendung speichern. Der Anwendungszustand ist ein globaler Speichermechanismus, auf den von allen Seiten der Webanwendung aus zugegrien werden kann. Der Anwendungszustand ist daher nützlich, um Informationen zu speichern, die zwischen Serverschleifen und zwischen Seitenanforderungen beibehalten werden müssen. Der Anwendungszustand wird in einem Schlüssel/Wert-Wörterbuch gespeichert, das während jeder Anforderung einer bestimmten URL erstellt wird. Sie können dieser Struktur die anwendungsspezischen Informationen hinzufügen, um sie zwischen Seitenanforderungen zu speichern. Nachdem Sie dem Anwendungszustand die anwendungsspezischen Informationen hinzugefügt haben, wird er vom Server verwaltet. Verwendungsempfehlungen nden Sie unter Empfehlungen zur ASP.NET-Zustandsverwaltung. Sitzungszustand: In ASP.NET können Sie mithilfe des Sitzungszustands, der eine Instanz der HttpSessionState-Klasse ist, Werte für jede aktive Webanwendungssitzung speichern. Eine Übersicht nden Sie unter Übersicht über den ASP.NET-Sitzungszustand. Der Sitzungszustand ist ähnlich dem Anwendungszustand, mit der Ausnahme, dass sich der Gültigkeitsbereich auf die aktuelle Browsersitzung erstreckt. Wenn die Anwendung von verschiedenen Benutzern verwendet wird, hat jede Benutzersitzung einen anderen Sitzungszustand. Wenn ein Benutzer die Anwendung verlässt und später wieder damit arbeitet, hat die zweite Benutzersitzung einen anderen Sitzungszustand wie die erste. ASP.NET enthält ein Feature mit dem Namen Proleigenschaften, mit dem Sie benutzerspezische Daten speichern können. Dieses Feature ähnelt dem Sitzungszustand, mit dem Unterschied, dass Proldaten nicht verloren gehen, wenn eine Benutzersitzung abläuft. Das Proleigenschaftenfeature verwendet ein ASP.NET-Prol, das in einem persistenten Format gespeichert und einem bestimmten Benutzer zugeordnet wird. Über das ASP.NET-Prol können Sie problemlos Benutzerinformationen verwalten, ohne eine eigene Datenbank erstellen und pegen zu müssen. Auÿerdem stellt das Prol die Benutzerinformationen mithilfe einer stark typisierten API zur Verfügung, auf die Sie von überall in Ihrer Anwendung zugreifen können. Sie können Objekte eines beliebigen Typs im Prol speichern. Das ASP.NET-Prolfeature stellt ein generisches Speichersystem dar, mit dem Sie praktisch alle Arten von Daten denieren und verwalten können. Trotzdem können Sie damit Daten typsicher zur Verfügung stellen. Um Proleigenschaften zu verwenden, müssen Sie einen Prolanbieter kongurieren. ASP.NET enthält eine SqlProleProvider-Klasse, mit der Sie Proldaten in einer SQL-Datenbank speichern können. Sie können jedoch auch eine eigene Prolanbieterklasse erstellen, die Proldaten in einem benutzerdenierten Format und mit einem benutzerdenierten Speichermechanismus speichert (z. B. in einer XML-Datei und sogar in einem Webdienst). Da in Proleigenschaften gespeicherte Daten nicht im Anwendungsspeicher gespeichert werden, bleiben sie auch bei Neustarts der Internetinformationsdienste (IIS) und des Workerprozesses vollständig erhalten. Auÿerdem können Proleigenschaften auch über mehre Prozesse hinweg erhalten bleiben, z. B. in einer Webfarm oder in einem Webgarten Konguration Mit den Features des ASP.NET-Kongurationssystems können Sie alle ASP.NET-Anwendungen auf einem kompletten Server, eine einzelne ASP.NET-Anwendung, einzelne Seiten oder Anwendungsunterverzeichnisse kongurieren. Zu den kongurierbaren Features gehören Authentizierungsmodi, Seitenzwischenspeicherung, Compileroptionen, benutzerdenierte Fehler, Debug- und Ablaufverfolgungsoptionen usw. Eine ausführliche Darstellung nden Sie unter Verwalten von ASP.NET-Websites. Schauen Sie sich die Kongurationsdateien Maschine.cong und Web.cong an. Aufgabe 7.1 Arbeiten Sie den Artikel Conguration Overview: ASP.NET im Anhang ab Seite 47 durch. Welche Kongurationsmöglichkeiten bietet Asp.Net? Aufgabe 7.2 Arbeiten Sie die Unterschiede und die Gemeinsamkeiten zwischen ASP.Net und PHP heraus. 63 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

64 7.2 Asp.Net MVC Ajax Ajax-Entwicklung ist mit VS2010 direkt in die IDE eingebunden. Die ASP.NET Ajax Library enthält vielfältige Controls und basiert auf der weit verbreiteten Bibliothek jquery. Sie können natürlich, wie in EWA eingeführt, eigene clientseitige Scripts erstellen und in Ihrere Applikation verwenden. Um die Ajax-Funktionalität einfach nutzen zu können, müssen Sie ein ScriptManager Control auf Ihre Seite platzieren. Mit diesem Control werden automatisch die benötigten Skriptbibliotheken auf den Client in der aktuellen Version geladen. Mithilfe eines UpdatePanel können Sie die Teile der Seite begrenzen, die sich ändern, wenn Benutzeraktionen normalerweise ein Postback verursachen würden. Häug werden mit Ajax Daten eines WCF-Services angezeigt. Die Theorie zu WCF nden Sie in Abschnitt 8 auf Seite In VS2010 können Sie ein neues Projekt auf Basis des Ajax-enabled WCF erzeugen und dort folgenden Code eingeben: Listing 7.1: Ajax-enabled WCF [ServiceContract(Namespace = " [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class CustomerService [OperationContract] public List<Customer> GetCustomers(int numbertofetch) using (NorthwindDataContext context = new NorthwindDataContext()) return context.customers.take(numbertofetch).tolist(); Speichern Sie dies als Service.svc ab. Mit dem DataView-Control können Sie diese Daten nun einfach anzeigen. <!DOCTYPE...> <html xmlns=" <head> <script type="text/javascript" src="scripts/microsoftajax.debug.js"></script> <script type="text/javascript" src="scripts/microsoftajaxtemplates.debug.js"></script> <script type="text/javascript" src="scripts/microsoftajaxadonet.debug.js"></script> </head> <body xmlns:sys="javascript:sys" xmlns:dataview="javascript:sys.ui.dataview" sys:activate="*"> <ul class="list sys-template" sys:attach="dataview" dataview:autofetch="true" dataview:dataprovider=" new Sys.Data.AdoNetServiceProxy('WebDataService1.svc') " dataview:fetchoperation="getcustomers" <li> ContactName </li> </ul> </body> </html> 7.2 Asp.Net MVC 2 Ein zentrales Thema in ASP.NET MVC 2.0 ist die Zusammensetzbarkeit von Websites aus Bausteinen. Nun kann der Entwickler einen View auf einfache Weise aus mehreren anderen Views zusammensetzen. Auÿerdem kann eine MVC-Anwendung mehrere Unteranwendungen (sogenannte Areas) mit eigenen Views, Controllern und Modellen besitzen, sodass sie eine eigenständige MVC-Anwendung bilden. Groÿe Webanwendungen werden somit überschaubarer und können besser in getrennten Teams entwickelt werden. Während bei den dynamischen Datenwebsites (Dynamic Data Websites) eine schnelle Lösung die oberste Maxime ist, zielt Microsoft mit dem im März 2009 veröentlichten ASP.NET Model View Controller Framework (Namensraum System.Web.Mvc) 1 WALKTHROUGH Using a DataView with server data 2 TechEd Europe 2009: Microsoft stellt ASP.NET MVC 2 vor 64 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

65 7.2 Asp.Net MVC auf klare Kompetenztrennung in lose gekoppelten, beliebig vielen Schichten, gute Test- und Wartbarkeit, die genaue Kontrolle über die Ausgabe und möglichst einfache, d.h. parameterlosen URLs. ASP.NET MVC folgt dem allgemeinen MVC-Ansatz. Das Modell besteht aus Geschäftsobjekten, Logik und Datenzugri. Views erzeugen die Benutzerschnittstelle und Aufgabe der Controller ist es, auf Benutzerinteraktionen zu reagieren und die dazu passenden Daten aus dem Modell mit den Views zusammenzubringen. Als Modell können wieder LINQ-to-SQL oder das ADO.NET EF zum Einsatz kommen das ist dann aber auch schon die einzige Gemeinsamkeit mit den dynamischen Datenwebsites. Controller sind Klassen, die von System.Web.Mvc.Controller abgeleitet sind und Aktionen in Form von Methoden implementieren. Sie nehmen die HTTP-Anfrage entgegen, wobei die Standardform /Controller/Aktion/Daten ist. So würde also in der Controller-Klasse Flug die Methode Edit() mit dem Parameter 103 aufrufen. Die Handhabung der vom Benutzer eingegebenen Daten würde eine gleichnamige Methode mit einem Parameter vom Typ FormCollection erledigen (siehe Listing 7). Den gröÿten Unterschied zu den dynamischen Datenwebsites und auch den ASP.NET-Webforms merkt man allerdings in den Views, denn für das MVC Framework gibt es nicht die komfortablen ASP.NET- Webserversteuerelemente. Stattdessen fällt MVC zurück in die Welt von puren HTML-Tags und eingewobenen Platzhaltern (< % =... % >) wie einst die klassischen Active Server Pages (ASP) und heute noch PHP. Wer eine Tabelle ausgeben will, kann sich also nicht auf die Abstraktion des GridView-Steuerelements stützen, sondern muss die HTML-Tags <table>, <tr>, <td> etc. verwenden und die zugehörige Schleife über die Datensätze explizit programmieren. MVC stellt lediglich zur Ausgabeerzeugung eine sehr bescheidene Anzahl von Hilfsroutinen wie Html.TextBox(), Html.DropDownList() und Html.ActionLink() zur Verfügung, die aber nur wenig Hilfe sind. Auch die Seitenzustandsverwaltung mit dem ASP.NET View State ist in MVC-Seiten nicht möglich, d.h. der Entwickler muss sich nun wieder selbst darum kümmern, dass zwischen zwei Aufrufen der gleichen Seite der Zustand der Seite wiederhergestellt wird. Auf der Haben-Seite notiert man dafür aber zum einen die volle Kontrolle über das erzeugte HTML und zum anderen die Vermeidung des erzwungenen Aufblähens der Webseite durch die Zustandsverwaltung. Die Views sind hierarchisch im Dateisystem organisierte.aspx-dateien, denen aber die sonst in ASP.NET üblichen Code-Behind-Dateien fehlen. Listing 8 zeigt einen einfachen View zur Bearbeitung bestehender Flug- Objekte. Erwähnt sein muss auch noch, dass es für die Views derzeit keinen Designer in Visual Studio gibt; hier ist also Handarbeit angesagt. Zwar spricht Microsoft auch bei MVC von Scaolding, meint hier aber anders als bei den dynamischen Datenwebsites eine einfache Codegenerierung zur Entwicklungszeit, die man in Visual Studio für Controller und View anstoÿen kann. Viele andere nicht an Webserversteuerelemente gebundene Dienste von ASP.NET Webforms wie die Vorlagenseiten, Authentizierung, Benutzerverwaltung, Sitzungsverwaltung, Zwischenspeicherung, Laufzeitüberwachung und Sitemaps stehen aber im MVC Framework zur Verfügung. Listing 7.2: ASP.Net MVC //Ausschnitt aus dem Controller "Flug" Public ActionResult Edit(int id) // Zu aktualisierender Flug aus Datenbank holen var movietoupdate = _db.flug.first(m => m.flugnr == id); ViewData.Model = movietoupdate; return View("Edit"); [AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(FormCollection form) // Zu aktualisierender Flug aus Datenbank holen int id = Int32.Parse(form["FlugNr"]); Flug flug = _db.flug.first(m => m.flugnr == id); // Deserialisieren TryUpdateModel(flug, new string[] "Abflugort", "Zielort", form.tovalueprovider()); // Validieren if (String.IsNullOrEmpty(flug.Abflugort)) ModelState.AddModelError("Abflugort", "Abflugort is required!"); if (String.IsNullOrEmpty(flug.Zielort)) ModelState.AddModelError("Zielort", "Zielort is required!"); // Speichern if (ModelState.IsValid) 65 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

66 7.2 Asp.Net MVC _db.savechanges(); return RedirectToAction("Index"); // Sonst, zeige Eingabeformular erneut an return View(flug); //View "/Flug/Edit.aspx" zur Eingabe von Flugdaten <form method="post" action="/flug/edit"> <%= Html.Hidden("FlugNr")%> FlugNr: <br /> <%= Model.FlugNr %> <br /> Abflugort: <br /> <%= Html.TextBox("Abflugort")%> <br /> Zielort: <br /> <%= Html.TextBox("Zielort")%> <br /> <input type="submit" value="save Flug" /> </form> Aufgabe 7.3 Arbeiten Sie den Artikel Erstellen von Webanwendungen ohne Webformulare im Anhang ab Seite 56 durch. 66 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

67 8 Windows Communication Foundation Abbildung 8.1: Assembly Was ist die Windows Communication Foundation? Was ist die Windows Communication Foundation? Die globale Akzeptanz von Webdiensten, wozu Standardprotokolle für Anwendung-zu-Anwendung-Kommunikation gehören, hat die Softwareentwicklung verändert. Beispielsweise gehören zu den Funktionen, die Webdienste nun bereitstellen, Sicherheit, Koordination verteilter Transaktionen und zuverlässige Kommunikation. Die Vorteile der Veränderungen im Bereich Webdienste sollten in den von Entwicklern verwendeten Hilfsmitteln und Technologien widergespiegelt werden. Windows Communication Foundation (WCF) ist darauf ausgelegt, einen verwaltbaren Ansatz zum verteilten Computing, zur weitreichenden Interoperabilität und für eine direkte Unterstützung der Dienstorientierung zu bieten. WCF erleichtert die Entwicklung von verbundenen Anwendungen durch ein neues dienstorientiertes Programmierungsmodell. WCF unterstützt durch seine Schichtenarchitektur viele Arten der Entwicklung verteilter Anwendungen. Auf der Basisschicht bietet die WCF-Kanalarchitektur asynchrone, nicht typisierte nachrichtenübertragende Stammfunktionen. Auf dieser Basisschicht benden sich Protokollfunktionen für einen sicheren, zuverlässigen, durchgeführten Datenaustausch und eine weitläuge Auswahl an Transport- und Codierungsoptionen. 8.1 Problembeispiel Im folgenden Beispiel werden einige der Probleme veranschaulicht, die WCF angeht. Ein Autovermieter entscheidet sich, eine neue Anwendung zum Reservieren von Autos zu erstellen. Die Entwickler dieser Reservierungsanwendung für Mietwagen wissen, dass es möglich sein muss, auf die von ihr implementierte Geschäftslogik über andere Software, sowohl innerhalb als auch auÿerhalb des Unternehmens, zuzugreifen. Daher entscheiden sie sich, auf dienstorientierte Weise zu programmieren, wobei die Logik der Anwendung anderer Software über einen denierten Satz von Diensten verfügbar gemacht wird. Zum Implementieren dieser Dienste und somit zum Kommunizieren mit anderer Software verwendet die neue Anwendung WCF. Mietwagen-Szenario: Während ihrer Lebensdauer wird voraussichtlich eine Reihe anderer Anwendungen auf die Mietwagen-Reservierungsanwendung zugreifen. Bei ihrer Programmierung wissen die Ersteller der Mietwagen-Reservierungsanwendung jedoch, dass drei andere Arten von Software auf ihre Geschäftslogik zugreifen werden: Eine Call-Center-Clientanwendung, die auf den Windows-Desktops läuft, mit denen die Mitarbeiter im Call-Center des Unternehmens arbeiten. Da diese Anwendung speziell für das neue Reservierungssystem erstellt wird, wird sie auch mit Microsoft.NET Framework und WCF programmiert. Diese Anwendung ist nicht wirklich unabhängig von der neuen Mitwagenreservierungs-Anwendung, da ihr einziger Zweck darin besteht, als Client für das neue System zu dienen. Aus dienstorientierter Perspektive ist sie nur ein weiterer Client für die Geschäftslogik des Reservierungssystems. 67

68 8.1 Problembeispiel Eine vorhandene Reservierungsanwendung, die auf einem J2EE-Server erstellt wird, der auf einem Nicht- Windows-System läuft. Aufgrund einer kürzlich stattgefundenen Fusion mit einem anderen Autovermieter muss das vorhandene System auf die Logik der neuen Anwendung zugreifen können, damit den Kunden der fusionierten Unternehmen eine einheitliche Umgebung geliefert wird. Partneranwendungen, die auf einer Vielzahl von Plattformen laufen, wobei sich jede in einem Unternehmen bendet, das ein geschäftliches Arrangement mit dem Autovermieter eingegangen ist. Zu den Partnern können Reisebüros, Fluggesellschaften und andere gehören, die für ihre Geschäfte Autovermietungsreservierungen vornehmen müssen. Die verschiedenartigen Kommunikationsanforderungen für die neue Mietwagen-Reservierungsanwendung sind nicht einfach. Für Interaktionen mit der Call-Center-Clientanwendung ist beispielsweise die Leistung wichtig, während die Interoperabilität unkompliziert ist, da beide auf.net Framework programmiert sind. Für die Kommunikation mit der vorhandenen J2EE-basierten Reservierungsanwendung und den verschiedenen Partneranwendungen ist jedoch die Interoperabilität von höchster Bedeutung. Auÿerdem sind die Sicherheitsanforderungen sehr unterschiedlich, da sie je nach den lokalen Windows-basierten Anwendungen, einer J2EE-basierten Anwendung, die auf einem anderen Betriebssystem läuft, und einer Vielzahl von Partneranwendungen, die über das Internet hereinkommen, variieren. Sogar Transaktionsanforderungen könnten variieren, wenn nur die internen Anwendungen Transaktionsanforderungen stellen dürfen. Wie können diese verschiedenen geschäftlichen und technischen Anforderungen erfüllt werden, ohne die Ersteller der neuen Anwendung vor unüberwindbare Schwierigkeiten zu stellen? WCF wurde für dieses komplexe, aber realistische Szenario entworfen und ist die Standardtechnologie für Windows-Anwendungen, die Dienste verfügbar machen und die auf sie zugreifen. Dieses Thema bietet eine Einführung in WCF, untersucht, was es bereitstellt und zeigt, wie es eingesetzt wird. In dieser Einführung dient das gerade beschriebene Szenario als Beispiel. Das Ziel ist es, deutlich zu machen, was WCF ist, welche Probleme es löst und zu zeigen, wie es diese Probleme löst. Angehen des Problems: Die Grundlage für neue Windows-basierte Anwendungen ist.net Framework. Dementsprechend wird WCF hauptsächlich als ein auf.net Framework-CLR aufbauender Satz von Klassen implementiert. Da es die ihnen bekannte Umgebung erweitert, ermöglicht es WCF den Entwicklern, die derzeit objektorientierte Anwendungen über.net Framework erstellen, auch dienstorientierte Anwendungen auf gewohnte Weise zu programmieren. Kommunikation zwischen einem WCF-Client und -Dienst: Wie das bereits beschriebene Szenario zeigt, dient WCF zum Lösen einer Reihe von Herausforderungen für kommunizierende Anwendungen. Drei Punkte sind jedoch eindeutig die wichtigsten Aspekte von WCF: Vereinigung vorhandener.net Framework-Kommunikationstechnologien. Unterstützung für anbieterübergreifende Interoperabilität, einschlieÿlich der Zuverlässigkeit, Sicherheit und Transaktionen. Explizite Dienstausrichtung. Da WCFs grundlegende Kommunikationsmechanismen SOAP-basierte Webdienste sind, können WCF-basierte Anwendungen mit anderer Software kommunizieren, die in einer Vielzahl an Kontexten läuft. Eine unter WCF erstellte Anwendung kann mit folgenden Anwendungen interagieren: WCF-basierten Anwendungen, die in einem anderen Prozess auf dem gleichen Windows-Computer ausgeführt werden. WCF-basierten Anwendungen, die auf einem anderen Windows-Computer ausgeführt werden. Auf anderen Technologien erstellten Anwendungen, z. B. J2EE-Anwendungsservern, die Standardwebdienste unterstützen. Diese Anwendungen können auf Windows-Computern oder auf Computern, auf denen andere Betriebssysteme laufen, ausgeführt werden. Um mehr als nur grundlegende Kommunikation zuzulassen, implementiert WCF Webdiensttechnologien, die durch WS-*-Spezikationen deniert werden. All diese Spezikationen wurden ursprünglich von Microsoft, IBM und anderen Anbietern in Zusammenarbeit deniert. Wenn sich diese Spezikationen durchsetzen, gehen sie oft in den Besitz von Standardgremien wie dem World Wide Web Consortium (W3C) oder der Organization for the Advancement of Structured Information Standards (OASIS) über. Diese Spezikationen betreen mehrere Bereiche, unter anderem grundlegendes Messaging, Sicherheit, Zuverlässigkeit, Transaktionen und das Arbeiten mit den Metadaten eines Diensts. Weitere Informationen nden Sie unter Interoperabilität und Integration. Weitere Informationen zu erweiterten Webdienstspezikationen nden Sie unter (möglicherweise in englischer Sprache). 68 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

69 8.2 Architektur 8.2 Architektur Abbildung 8.2: Assembly Windows Communication Foundation-Architektur Verträge und Beschreibungen Verträge denieren verschiedene Aspekte des Nachrichtensystems. Der Datenvertrag beschreibt alle Parameter, aus denen die einzelnen Nachrichten bestehen, die ein Dienst erstellen oder verarbeiten kann. Die Nachrichtenparameter werden in XSD-Dokumenten (XML-Schemadenitionssprache) deniert. Dadurch kann jedes XMLfähige System die Dokumente verarbeiten. Der Nachrichtenvertrag deniert anhand von SOAP-Protokollen bestimmte Nachrichtenteile und ermöglicht eine detailliertere Steuerung der Teile einer Nachricht, wenn die Interoperabilität diese Genauigkeit verlangt. Der Dienstvertrag gibt die tatsächlichen Methodensignaturen des Dienstes an und wird als Schnittstelle in einer der unterstützten Programmiersprachen verteilt (z. B. Visual Basic oder Visual C#). Richtlinien und Bindungen legen die zur Kommunikation mit einem Dienst erforderlichen Bedingungen fest. Beispielsweise muss die Bindung (mindestens) den verwendeten Transport (z. B. HTTP oder TCP) und eine Codierung angeben. Richtlinien schlieÿen Sicherheitsanforderungen und andere Bedingungen ein, die für die Kommunikation mit einem Dienst erfüllt werden müssen Dienstlaufzeit Die Dienstlaufzeitebene umfasst Verhaltensweisen, die nur während der tatsächlichen Ausführung des Dienstes auftreten, d. h. das Laufzeitverhalten des Dienstes. Die Drosselung steuert, wie viele Nachrichten verarbeitet werden. Diese Zahl kann geändert werden, wenn die Nachfrage nach dem Dienst ein voreingestelltes Limit erreicht. Für den Fall eines internen Dienstfehlers gibt das Fehlerverhalten die zu ergreifenden Maÿnahmen an, z. B. indem es steuert, welche Informationen an den Client übermittelt werden. (Zu viele Informationen könnten einem böswilligen Benutzer einen Angri erleichtern.) Das Metadatenverhalten bestimmt, wie und ob Metadaten öentlich verfügbar gemacht werden. Wie viele Instanzen des Dienstes ausgeführt werden können, wird vom Instanzenverhalten angegeben (Singleton gibt z. B. nur eine Instanz zur Verarbeitung aller Nachrichten an). Das Transaktionsverhalten ermöglicht einen Rollback von durchgeführten Vorgängen im Fall eines Fehlers. Mit dem Verteilungsverhalten wird die Verarbeitung von Nachrichten durch die WCF-Infrastruktur gesteuert. Die Erweiterbarkeit ermöglicht eine Anpassung der Laufzeitprozesse. Beispielsweise werden mit der Nachrichteninspektion Teile einer Nachricht überprüft, und mit der Parameterlterung nden anhand von Filtern, die auf Nachrichtenheader angewendet werden, voreingestellte Aktionen statt Messaging Die Messagingebene besteht aus Kanälen. Ein Kanal ist eine Komponete, die eine Nachricht in bestimmter Weise verarbeitet, z. B. durch Authentizierung. Ein Reihe von Kanälen wird auch Kanalstapel genannt. Kanäle arbeiten mit Nachrichten und Nachrichtenheadern. Die Dienstlaufzeitebene hingegen verarbeitet hauptsächlich den Inhalt des Nachrichtentexts. Es gibt zwei Arten von Kanälen: Transportkanäle und Protokollkanäle. 69 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

70 8.2 Architektur Transportkanäle lesen und schreiben Nachrichten aus dem Netzwerk (oder einem Kommunikationspunkt zur Auÿenwelt). Bei einigen Transporten wird ein Encoder verwendet, um Nachrichten (die als XML-Infosets dargestellt werden) in und aus der Bytestreamdarstellung des Netzwerks zu konvertieren. HTTP, benannte Pipes, TCP und MSMQ sind Beispiele für Transporte. Beispiele für Codierungen sind XML und optimierte Binärdateien. Protokollkanäle implementieren Nachrichtenverarbeitungsprotokolle. Das erfolgt häug durch Lesen oder Schreiben zusätzlicher Header in die Nachricht. Zu diesen Protokollen gehören beispielsweise WS-Security und WS-Reliability. Die Messagingebene stellt die möglichen Formate und die Austauschmuster der Daten dar. WS-Security ist eine Implementierung der WS-Security-Spezikation, die die Sicherheit auf der Nachrichtenebene aktiviert. Der WS-Reliable Messaging-Kanal stellt die Nachrichtenübermittlung sicher. Mit einer Vielzahl von Codierungen ermöglichen es Encoder, die Nachrichtenanforderungen zu erfüllen. Der HTTP-Kanal gibt die Verwendung des Hypertextübertragungsprotokolls zur Nachrichtenübermittlung an. Entsprechend gibt der TCP-Kanal die Verwendung des TCP-Protokolls an. Der Transaktionsusskanal bestimmt die Muster von Transaktionsnachrichten. Der Kanal für benannte Pipes ermöglicht die prozessübergreifende Kommunikation. Der MSMQ-Kanal ermöglicht die Interoperation zwischen MSMQ-Anwendungen Hosting und Aktivierung Ein Dienst ist letztendlich ein Programm. Wie andere Programme muss ein Dienst in einer ausführbaren Datei ausgeführt werden. Dabei handelt es sich um einen so genannten selbst gehosteten Dienst. Dienste werden jedoch auch gehosted oder in einer ausführbaren Datei von einem externen Agent verwaltet ausgeführt, z. B. IIS oder Windows Activation Services (WAS). WAS ermöglicht es, WCF-Anwendungen auf Computern, auf denen WAS ausgeführt wird, automatisch zu aktivieren. Sie können Dienste gegebenenfalls manuell als ausführbare Dateien (EXE-Dateien) ausführen. Ein Dienst kann auch automatisch als Windows-Dienst ausgeführt werden. Auch COM+-Komponenten können als WCF-Dienste gehostet werden. Ein einfaches Beispiel für einen Ajax-fähigen WCF-Dienst nden Sie in Abschnitt 7.1 auf Seite c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

71 9 Windows Workow Foundation 1 Windows Workow Foundation (WF) ist ein Framework, das Benutzern das Erstellen von system- oder benutzerbezogenen Workows in ihren Anwendungen für die Betriebssysteme Windows Vista, Windows XP und Windows Server 2003 ermöglicht. Es besteht aus einem Namespace, einem prozessinternen Workowmodul und Designern für Visual Studio. Windows Workow Foundation kann sowohl in einfachen Szenarios (z. B. zum Anzeigen bestimmter Benutzeroberächensteuerelemente in Abhängigkeit von Benutzereingaben) als auch in komplexen Szenarios (z. B. zur Bestellabwicklung und Lagerverwaltung) eingesetzt werden. Windows Workow Foundation umfasst ein Programmiermodell, ein neu zu hostendes und anpassbares Workowmodul und die Tools zum schnellen Erstellen workowfähiger Anwendungen unter Windows. Zu den Szenarios, für die die Windows Workow Foundation eingesetzt werden kann, zählen Folgende: Aktivieren von Workows innerhalb von Branchenanwendungen Benutzeroberächen-Pageows Dokumentorientierte Workows Benutzerbezogene Workows Zusammengesetzte Workows für dienstorientierte Anwendungen Geschäftsregelbasierte Workows Systemverwaltungsworkows Gehen wir einen Schritt zurück. Was ist ein Workow? Ein Workow ist eine Folge von Schritten, Entscheidungen und Regeln, die abgearbeitet werden müssen, um eine bestimmte Aufgabe zu erledigen. Aufgabe 9.1 Beschreiben Sie die Schritte, Entscheidungen und Regeln, die für die Anmeldung zu einer Prüfung notwendig sind. Microsoft nennt die einzelnen Schritte eines Workows Activities. Ein Workowprojekt ist keine eigentliche Anwendung, sondern benötigt immer einen Host, eine Asp.Net Applikation kann beispielsweise ein solcher Host sein. Denken Sie beispielsweise an mögliche Verzweigungen in einer Web-Applikation, je nach Benutzereingaben werden Sie auf eine andere Seite geleitet. Auch ein Neustart des Betriebssystems beendet einen Workow nicht. Warum? Es werden zwei Arten von Workows unterschieden: Statuscomputerworkows und Sequenzielle Workows. 9.1 Statuscomputerworkows 2 Im Statuscomputerformat der Workowerstellung modelliert der Autor den Workow als Statuscomputer. Der Workow selbst besteht aus einer Reihe von Zuständen. Ein Zustand wird als Ausgangszustand bezeichnet. Jeder Zustand kann einen bestimmten Satz Ereignisse erhalten. Auf Grundlage eines Ereignisses kann ein Übergang zu einem anderen Zustand erfolgen. Der Statuscomputerworkow kann über einen Endzustand verfügen. Beim Übergang zum Endzustand wird der Workow abgeschlossen. Das folgende Flussdiagramm ist ein Beispiel für einen Statuscomputerworkow. Folgende Aktivitäten stehen out of the box zur Verfügung: EventDrivenActivity Wird für Zustände verwendet, die für die Ausführung ein externes Ereignis benötigen. Die EventDrivenActivity-Aktivität muss über eine Aktivität verfügen, mit der die IEventActivity- Schnittstelle als erste untergeordnete Aktivität implementiert wird. Weitere Informationen nden Sie unter Verwenden der EventDrivenActivity-Aktivität. 1 Übersicht über die Windows Workow Foundation 2 Statuscomputerworkows 71

72 9.2 Sequenzielle Workows Abbildung 9.1: Beispiel für einen Statuscomputerworkow SetStateActivity Gibt einen Übergang zu einem neuen Zustand an. Weitere Informationen nden Sie unter Verwenden der SetStateActivity-Aktivität. StateActivity Stellt einen Zustand auf einem Statuscomputer dar; enthält möglicherweise zusätzliche Zustandsaktivitäten. Weitere Informationen nden Sie unter Verwenden der StateActivity-Aktivität. StateInitializationActivity Wird ausgeführt, wenn ein Zustand eintritt. Enthält möglicherweise andere Aktivitäten. Weitere Informationen nden Sie unter Verwenden der StateInitializationActivity-Aktivität. StateFinalizationActivity Führt beim Verlassen einer StateActivity-Aktivität enthaltene Aktivitäten aus. Weitere Informationen nden Sie unter Verwenden der StateFinalizationActivity-Aktivität. 9.2 Sequenzielle Workows 3 Mit dem sequenziellen Workowformat wird eine Reihe enthaltener Aktivitäten der Reihenfolge nach ausgeführt. Sie können einem sequenziellen Workow andere zusammengesetzte Aktivitäten hinzufügen, um Folgendes zu erreichen: Parallelismus (ParallelActivity), ereignisgesteuerten Parallelismus (EventHandlingScopeActivity), datengesteuerte Ausführung (ConditionedActivityGroup), ereignisgesteuerte Verzweigung (ListenActivity) und vertraute imperative Ablaufsteuerungsmuster wie bedingte Verzweigung (IfElseActivity) und Iteration (WhileActivity, ReplicatorActivity). Zudem können benutzerdenierte zusammengesetzte Aktivitäten geschrieben werden, mit denen spezielle Ablaufsteuerungsmuster implementiert werden. Das folgende Flussdiagramm zeigt ein Beispiel eines sequenziellen Workows. Abbildung 9.2: Beispiel für einen sequenziellen Workow Ein sequenzieller Workow führt Aktivitäten bis zur Fertigstellung der letzten Aktivität sequenziell aus. Sequenzielle Workows sind auch im normalen Betrieb nicht notwendigerweise vollständig deterministisch. Beispielsweise kann eine ListenActivity-Aktivität oder eine ParallelActivity-Aktivität verwendet werden, wobei die genaue Reihenfolge der Ereignisse in diesen Fällen variieren kann. 3 Sequenzielle Workows 72 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

73 10.Net Framework Im letzten Jahrtausend wurde Cliententwicklung im Microsoftumfeld hauptsächlich mit VB6 betrieben. VB6 ist eine prozedurale interpretierte Sprache, mit der schon Vieles ging. Die aber die Entwicklung der Softwareentwicklung (OO, Modellierung,...) nicht mitmachen konnte. Zusätzlich wurden performante Komponenten in C++ entwickelt. Die Kommunkation zwischen den Komponenten wurde oft über COM realisiert. Die Konvertierung von Datentypen in VB6 und C++ war ein gängiges Problem. Auch die Installation und das Update von Komponenten machte immer wieder Probleme (Versionskonikte, Registry). Der Siegeszug von Java mit der Virtual Maschine und der damit verbundenen Plattformunabhängigkeit war ein groÿes Vorbild. Microsoft hat viel von Java übernommen, einige Features dazu gepackt und daraus ein eigenes Framework entwickelt..net adressiert die folgenden bis dahin aktuellen Probleme: Austausch von Variablen/Objekten zwischen verschiedenen Komponenten, die evtl. in verschiedenen Programmiersprachen implementiert sind. Interoperabilität, d.h. standardisierte Protokolle, Datenformate (XML-basiert) Zustandslosigkeit des Webs Ungleiche Programmierschnittstellen, zu viele APIs (COM, Win32, Microsoft Foundation Classes,...) Speicherverwaltung Routinetätigkeiten, Implementation ähnlicher wiederkehrender Probleme Softwareverteilung (Deployment) Durch Mono gibt es.net nicht nur für Windows, sondern auch für Unix/Linux. Die Entwickler von Mono sind sehr aktiv, so gibt es jetzt schon eine Unterstützung von.net was erst im April ausgerollt wird. Im Originalton von Microsoft liest sich das wie folgt.net:.net Framework ist eine integrale Windows- Komponente, die die Entwicklung und Ausführung von Anwendungen und XML-Webdiensten der nächsten Generation unterstützt..net Framework wurde im Hinblick auf folgende Zielsetzungen entwickelt: Bereitstellung einer konsistenten, objektorientierten Programmierumgebung, in der Objektcode gespeichert wird. Die Ausführung erfolgt dann entweder lokal oder über Remotezugri bzw. lokal mit Verteilung über das Internet. Bereitstellung einer Codeausführungsumgebung, mit der Konikte bei der Softwarebereitstellung und Versionskonikte auf ein Minimum beschränkt werden. Bereitstellung einer Codeausführungsumgebung, die eine sichere Ausführung ermöglicht, und zwar auch von Code, der von unbekannten oder nur halb-vertrauenswürdigen Dritten erstellt wurde. Bereitstellung einer Codeausführungsumgebung, die nicht mehr die bei interpretations- oder skriptbasierten Umgebungen auftretenden Leistungsprobleme aufweist. Schaung einer konsistenten Entwicklungsumgebung für die verschiedensten Anwendungsarten, wie beispielsweise Windows- und webbasierte Anwendungen. Aufbau der gesamten Kommunikation auf Industriestandards, um die Integration von Code, der auf.net Framework basiert, in jeden anderen Code zu gewährleisten. 73

74 10.1 Vokabeln 10.1 Vokabeln Grundlage ist die Common Language Infrastructure (CLI), die auch bei Standard ECMA-335 deniert ist: Partition I: Konzepte und Architektur Beschreibt die Gesamtarchitektur der CLI. Speziziert dazu das Common Type System (CTS), das Virtual Execution System (VES) und die Common Language Specication (CLS). Partition II: Metadatendenition und Semantik Enthält Informationen über Metadaten: Das physische Layout der Dateien, die logischen Inhalte und deren Struktur. Partition III: CIL Beschreibt die Instruktionen der Common Intermediate Language (CIL). Partition IV: Bibliotheken Enthält eine Spezikation von Klassen und Klassenbibliotheken, die als Teil der CLI standardisiert sind. Partition V: Beschreibt das einheitliche Debuggingformat. Partition VI: Anhänge. Abbildung 10.1: CTS in Relation zu CLS Das Common Type System (CTS) ist die Gesamtmenge aller möglichen Eigenschaften und Typen (siehe Abbildung 10.3). Die Common Language Specication (CLS) ist eine Untermenge der CTS-Eigenschaften und Typen, die von jedem Compiler unterstützt werden müssen, um die Interoperabilität zwischen der.net Applikationen zu garantieren. Nicht CLS-konforme Typen sind beispielsweise Int8 oder Unsigned int64. Die CLS stellt einen Satz von Merkmalen sicher, die in jeder Sprache, die in die Laufzeitumgebung integriert wird, garantiert zur Verfügung stehen. Die CLS garantiert, dass jedes Programm bzw. jeder Programmteil (z. B. eine einzelne Klasse), der CLS-konform entwickelt worden ist, in jeder anderen CLS-kompatiblen Programmiersprache vollständig genutzt werden kann 1. Beispielsweise gibt es nur einen unicode-basierten Stringtyp und alles ist ein Objekt. Dadurch ist die.net Plattform selbst sprachneutral und jede der dort verwendeten Sprachen ist gleich berechtigt. Momentan sind 57 Sprachen bei Wikipedia (Liste von.net-sprachen) gelistet, die in einer modizierten Implementation, im.net Framework laufen. Darunter nden sich PHP, Python, Prolog, Fortran, Java, Perl und Ruby. Ähnlich zur Java Virtual Maschine gibt es bei.net eine Common Language Runtime (CLR), die alles zur Verfügung stellt, damit Komponenten miteinander interagieren können. Sie erzeugt Objekte, übernimmt Methodenaufrufe und verwaltet Speicher, Prozesse und Sicherheit. Abbildung?? zeigt wie das Framework arbeitet. Mit einem Vorcompiler wird Programmcode in die Common Intermediate Language (CIL) (teilweise auch nur Intermediate Language (IL) genannt) übersetzt. CIL ist eine objektorientierte Assemblersprache. Das physikalische Ergebnis dieses Compilevorgangs sind die sogenannten Assemblies (siehe Abschnitt 10.2 auf Seite 78). Die Assemblies benden sich im lokalen Verzeichnis oder sind im Global Assembly Cache (GAC) registriert. Der Just in time compiler (JIT) erzeugt daraus sogenannten Managed Code, der in der Common Language Runtime (CLR) für das jeweilige Betriebssystem umgesetzt wird. 1 Die Regeln der CLS gelten dabei immer nur für öentliche (public oder protected) Schnittstellen. 74 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

75 10.1 Vokabeln Abbildung 10.2: Ausführungsmodell Managed Code ist per Denition Code, der von der CLR interpretiert wird. Jeder andere Code ist unmanaged. Unmanaged Code unterliegt also nicht der Aufsicht der CLR, ist plattformabhängig und typischerweise ohne das.net Framework erstellt. Der durch den JIT-Compiler erstellte Maschinencode wird bei Beendigung des Prozesses, der die ausführbare Datei ausführt, verworfen. Daher muss die Methode beim erneuten Ausführen der Anwendung wieder neu kompiliert werden. NGen erlaubt die Vorkompilierung von CIL-Anwendungen in Maschinencode vor der Ausführungszeit typischerweise während der Installation. Dies führt zu zwei wesentlichen Leistungsvorteilen. Erstens wird die Dauer zum Starten der Anwendung verringert, da eine Kompilierung zur Ausführungszeit vermieden wird. Zweitens wird die Speichernutzung verbessert, da ein gemeinsames Verwenden der Codepages durch mehrere Prozesse unterstützt wird. Obwohl NGen auf den ersten Blick einer herkömmlichen statischen Back-End-Kompilierung zu entsprechen scheint, ist es tatsächlich etwas ganz anderes. Im Unterschied zu statisch kompilierten Binärdateien werden NGen-Images an die Maschine gebunden, auf denen sie erstellt wurden, und können daher nicht allgemein bereitgestellt werden. Stattdessen muss das Installationsprogramm einer Anwendung Befehle ausführen, um systemeigene Images der jeweiligen Assemblys auf dem Clientcomputer zu erstellen (ausführlichere Artikel: Die Leistungsvorteile durch NGen NGen Revs Up Your Performance with Powerful New Features). Abbildung 10.3: Speicherverwaltung Der Garbage Collector der CLR verwaltet die Reservierung und Freigabe von Arbeitsspeicher für die Anwendung. Wenn Sie den Operator new zum Erstellen eines Objekts verwenden, reserviert die CLR Arbeitsspeicher für das Objekt auf dem verwalteten Heap. Solange ein Adressbereich im verwalteten Heap verfügbar ist, reserviert die Laufzeit Arbeitsspeicher für neue Objekte. Arbeitsspeicher ist jedoch nicht unendlich verfügbar. Möglicherweise muss mithilfe der Garbage Collection Arbeitsspeicher freigegeben werden. Das Optimierungsmodul der Garbage Collection bestimmt den besten Zeitpunkt für das Einsammeln anhand der erfolgten Reservierungen. Beim Einsammeln durch die Garbage Collection wird nach Objekten im verwalteten Heap gesucht, die nicht 75 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

76 10.1 Vokabeln mehr von der Anwendung verwendet werden. Anschlieÿend werden die für das Freigeben des Arbeitsspeichers erforderlichen Operationen ausgeführt. Dafür weiÿ man nicht, wann der Speicher wirklich freigegeben wird. Das Framework bietet auch direkten Zugri auf den GC, damit sollte man jedoch sehr sehr vorsichtig umgehen. Garbage Collector: gibt Speicher aller Objekte frei, auf die kein Verweis mehr existiert. Eine genaue Beschreibung der Arbeitsweise des GC in C# bzw. Java nden Sie im Anhang auf Seite 84. Aufgabe 10.1 Beschreiben Sie die wesentlichen Phasen im Lebenszyklus eines Objekts. Klären Sie die Begrie Stack, Heap, managed Heap, Wie ist die prinzipielle Arbeitsweise des GC? Wie viele Generationen werden verwaltet? Was landet auf dem Stack, was auf dem Heap? Lesen Sie auch den Artikel des GC in Java: Gibt es prinzipielle Unterschiede, wenn ja, welche? Das Sicherheitsmodell der CLR deckt folgende Bereiche ab: Typsicherheit: C# erlaubt Zeiger nur innerhalb eines unsafe-blocks, Basis ist die CLS. Die CLR führt eine Typsicherheitsprüfung während des JIT-Vorgangs durch und weigert sich bei Fehlern, diesen auszuführen. Sie ist manuell durchführbar mittels PEVerify.exe. Code-Signierung ermöglicht es Sicherheitseinschränkungen für Assemblies und Code zu denieren. Diese Einschränkungen und Regeln werden von der CLR erzwungen und sowohl durch die Entwicklerin als auch durch die Systemadministratorin deniert. Kryptographie Code Access Security (CAS) Abbildung 10.4: Code Access Security, Quelle: Uni Karlsruhe, Microsoft.Net Sicherheit Abbildung 10.4 CAS schützt den Zugri auf Systemresourcen über Berechtigungen (Permissions). Berechtigungen können mit Hilfe eines Berechtigungsatzes (Permission Set) gruppiert werden. Dieser Vorgang ist mit den von Windows her bekannten Benutzern und Benutzergruppen vergleichbar. Ein Berechtigungssatz ist dabei grundsätzlich einer Codegruppe (Code Group) zugeordnet. Eine Code-Gruppe ist eine logische Einstufung von Code anhand einer Bedingung, z.b. alle Assemblies von gehören zur Gruppe SomeCode. Sobald ein Assembly geladen wird, untersucht die CLR dieses Assembly und legt fest, welche Codemerkmale (Evidence) es besitzt Standardmäÿig sind im.net Framework insgesamt sieben verschiedene Codemerkmale vordeniert: Application Directory, Hash, Publisher, Site, Strong Name, URL und Zone. Die Zuordnung eines Codemerkmals zu einer Codegruppe und damit den Rechten, die das Assembly zur Laufzeit erhält erfolgt über die sogenannte Zugehörigkeitsbedingung (Membership Condition). Wichtig dabei: Besitzt ein Assembly mehrere 76 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

77 10.1 Vokabeln Codemerkmale, wird es auch mehreren Codegruppen gleichzeitig zugeordnet. Die jeweiligen Rechtemengen werden dabei zu einer Vereinigungsmenge zusammengeführt (ODER-Verknüpfung)! Durch dieses Verhalten kann ein Assembly mehr Rechte zugewiesen bekommen, als ursprünglich vorgesehen. Aus diesem Grund kann eine Codegruppe mit dem Attribut exklusiv versehen werden. Das Assembly bekommt dann nur die Berechtigungen dieser einzelnen Gruppe zugewiesen. Mit PermView.exe kann man analysieren, welche Rechte ein Programm benötigt. Der Lader liest die Metadaten und legt im Hauptspeicher eine interne Repräsentation der Klassen und seiner Mitglieder an. Eine Klasse wird nur dann geladen, wenn sie auch referenziert wird. Abbildung 10.5: Zusammenspiel von Loader, CAS und GAC (Quelle:Microsoft.NET Framework Runtime, Teil 1: Die ausführung von Assemblys) Abbildung 10.5 zeigt, wie und wann die CLR Sicherheitschecks durchführt. Einen ausführlichen Artikel hierzu nden Sie unter Understanding The CLR Binder. Auch die Fehlerbehandlung passiert in der CLR. Früher gab es diverse Methoden, wie Win32 Error Codes, COM HRESULTs oder in VB6 On Error GoTo. Dabei war es problematisch, dass diese leicht zu ignorieren und nicht strukturiert waren, zu wenig Informationen enthielten und nicht sprach- und technologieübergreifend zur Verfügung standen. Exceptions der CLR lösen dies auf: Signalisiert ein Objekt einen Ausnahmezustand, so ist diese Ausnahme einheitlich für alle.net Sprachen, müssen behandelt werden, können vererbt werden (über Sprachgrenzen hinaus) und enthalten Zusatzinformationen (Stacktrace). Nicht behandelte Ausnahmen werden an die aufrufende Komponente weitergereicht. 77 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

78 10.2 Assembly 10.2 Assembly Abbildung 10.6: Assembly Microsoft deniert ein Assembly so: Assemblies sind die Grundbausteine von.net Framework-Anwendungen. Sie bilden die Basiseinheit für Weitergabe, Versionskontrolle, Wiederverwendung, Aktivierungs-Scoping und Sicherheitsberechtigungen. Eine Assembly ist eine Auistung von Typen und Ressourcen, die so erstellt wurden, dass sie zusammenarbeiten und eine logische funktionelle Einheit bilden. Eine Assembly stellt der Common Language Runtime die für das Erkennen von Typimplementierungen erforderlichen Informationen zur Verfügung. Für die Common Language Runtime sind Typen nur im Kontext einer Assembly vorhanden. Quelle: Assemblies kurz und knapp. Ein Assembly ist somit... eine Menge von Typen, die zusammenkompiliert werden, inklusive Ressourcen wie Bilder. eine Laufzeiteinheit, die als Datei gespeichert wird (*.exe oder *.dll), auch portable Executable (PE) genannt. die kleinste Einheit in Bezug auf Deployment, dynamischem Laden, Sicherheit Versionierung enthält Code (objekorientierter Assemblercode) enthält Metadaten enthält ein Manifest (Inhaltsverzeichnis) ist vergleichbar mit einer Java JAR-Datei ist eine.net Komponente Man unterscheidet zwischen privaten und öentlichen Assemblies. Öentliche Assemblies werden im GAC registriert, was zur Folge hat, dass sie über einen strong name verfügen müssen. Ein solcher Name ist eindeutig, ähnlich einer GUID. Assemblies im GAC stehen allen Applikationen zur Verfügung. Private Assemblies benden sich im Verzeichnis der Applikation, können nur von dieser Applikation verwendet werden und können nicht signiert werden. Der GAC ist ein sicherer Speicher, der verschiedene Versionen einer Assembly enthalten kann. Ein Strong Name setzt sich aus vier Teilen zusammen: Dateiname, z.b. db.dll Versionsnummer, z.b c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

79 10.2 Assembly der Kultur (de-de, en-us,...), Sprach und länderspezische Information einem öentlichen Schlüssel Die Metadaten enthalten den public key, Informationen über exportierte Typen (Name, Sichtbarkeit, Basisklasse, implementierte Interfaces, Members, Attribute), Abhängigkeiten zu anderen Assemblies und Sicherheitseinstellungen. Abbildung 10.7: Der Assembly Resolver im Detail, Quelle: Assemblies Pakete einer.net Anwendung Abbildung 10.7 zeigt, wie die richtige Version einer Assembly gesucht wird. Wenn verwalteter Code höhere Berechtigungen verlangt, ist es besser, diesen Code in einer anderen Assembly als den Code zu speichern, für den die höheren Berechtigungen nicht erforderlich sind. Bei der Assemblysicherheit unterscheidet man drei Arten: SAFE ist der Standardberechtigungssatz und die restriktivste Einstellung. Code, der von einer Assembly mit SAFE-Berechtigungen ausgeführt wird, kann nicht auf externe Systemressourcen wie z. B. Dateien, das Netzwerk, Umgebungsvariablen oder die Registrierung zugreifen. SAFE-Code kann auf Daten aus den lokalen SQL Server-Datenbanken zugreifen oder Berechnungen und Geschäftslogik ausführen, für die kein Zugri auf Ressourcen auÿerhalb der lokalen Datenbanken erforderlich ist. Die meisten Assemblys führen Berechnungs- und Datenverwaltungsaufgaben aus, ohne dass ein Zugri auf Ressourcen auÿerhalb erforderlich ist. Aus diesem Grund wird empfohlen, SAFE als Berechtigungssatz für die Assembly zu verwenden. EXTERNAL_ACCESS ermöglicht Assemblys den Zugri auf bestimmte externe Systemressourcen wie z. B. Dateien, Netzwerke, Webdienste, Umgebungsvariablen und die Registrierung. SAFE- und EXTERNAL_ACCESS-Assemblys können nur Code enthalten, der überprüfbar typsicher ist. Dies bedeutet, dass diese Assemblys auf Klassen nur über denierte Einstiegspunkte zugreifen können, die für die 79 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

80 10.3 Anwendungsdomäne (AppDomain) Typdenition gültig sind. Daher können sie nicht beliebig auf Speicherpuer zugreifen, die sich nicht im Besitz des Codes benden. UNSAFE ermöglicht Assemblys den uneingeschränkten Zugri auf Ressourcen. Code, der aus einer UNSAFE-Assembly ausgeführt wird, kann nicht verwalteten Code aufrufen. Wenn Sie UNSAFE angeben, kann der Code in der Assembly auÿerdem Vorgänge ausführen, die von der CLR-Überprüfung als typunsicher betrachtet werden. UNSAFE-Assemblys können auÿerdem potenziell das Sicherheitssystem der CLR unterlaufen. UNSAFE-Berechtigungen sollten nur hochgradig vertrauenswürdigen Assemblys durch erfahrene Entwickler oder Administratoren erteilt werden. Nur Mitglieder der festen Serverrolle sysadmin können UNSAFE-Assemblys erstellen. Immer dann, wenn Sie innerhalb einer Assembly auf Nicht-.Net-Code, wie z.b. COM-Komponenten zugreifen möchten, müssen Sie leider UNSAFE wählen Anwendungsdomäne (AppDomain) Anwendungsdomänen sind isolierte Bereiche im CLR-Prozess. Sie werden auch als leichtgewichtige Unterprozesse oder Pseudoprozesse bezeichnet. Wichtig ist, sie sind KEINE Prozesse! Innerhalb der CLR gibt es keine Hardware-Kapselung. Anwendungsdomänen... Schirmen Applikationen gegeneinander ab Umfassen (und isolieren) Assemblies, Module und Typen einer Applikation, Methodentabellen der geladenen Typen und Statische Felder und Objekte der geladenen Typen Können entweder direkt im Code (System.AppDomain.CreateDomain) oder vom jeweiligen Host der CLR erzeugt werden. Es gibt keine direkte Kommunikation zwischen Anwendungsdomänen. Es ist auch kein direkter Zugri auf Assemblies anderer Anwendungsdomänen möglich. Die CLR verhindert die Übergabe von Objekt- Referenzen zwischen Anwendungsdomänen. Eine Interaktion ist nur über einen speziell gesicherten Inter- Domain-Kommunikationsmechanismus möglich. Bei dem Prinzip der Anwendungsdomänen werden verschiedene Anwendungen oder Ausführungseinheiten in den gleichen Prozessraum geladen und in verschiedene Subprozesse gekapselt. Hierdurch entfallen Leistungeinbuÿen durch Prozesswechsel. Die.NET Laufzeitumgebung sorgt dafür, dass die einzelnen Anwendungsdomänen nicht in den Speicherbereich anderer Anwendungen im gleichen Prozessraum schreiben. Typischerweise arbeitet man nur mit einer Anwendungsdomäne. Mehrere Anwendungsdomänen sind erforderlich, wenn Code mit anderen Sicherheits-Einstellungen/Zugrisrechten geladen wird, die Isolation zwischen Code-Teilen explizit gewünscht wird, oder Code unabhängig voneinander terminieren können soll. Für Plug-Ins beispielsweise bieten sich separate Anwendungsdomänen an, also eine AppDomain pro Plug-In. Das Stichwort zur Kommunikation zwischen verschiedenen Anwendungsdomänen ist Remoting. Remoting ist die Bezeichnung für (Netzwerk)komunikation der Programmiersprache C#. Kommunikation zwischen Objekten in verschiedenen AppDomains oder in Prozessen auf verschiedenen Computern wird ermöglicht. Abbildung?? Wie genau, die Kommunikation zwischen verschiedenen Anwendungsdomänen erfolgt beschreibt der Artikel Baukasten für verteilte Anwendungen: Marshalling: Sobald ein Aufruf eine Appdomain-Grenze überschreitet ist Marshalling notwendig. Oder anders formuliert: Die Remoting-Mechanismen greifen. Bild?? zeigt diesen Zusammenhang. Das Marshalling 2 kann dabei entweder by Value oder by Reference erfolgen und es kommt die zweite,wichtige Regel ins Spiel: Marshalling ist immer mit Serialisierung und Deserialisierung verbunden. 2 Marshalling ist das Verpacken eines Programmcodeaufrufs in eine Nachricht, sodass ein Aufruf zwischen zwei Programmen möglich ist, die keinen gemeinsamen Speicher besitzen. 80 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

81 10.4 Basisklassen Abbildung 10.8: Beschreibung Basisklassen Ein Namensraum ist ein logisches Benennungsschema zum Gruppieren von verwandten Typen. In einer Datei können mehrere Klassen und mehrere Namensräume deniert werden dies erhöht sicher nicht die Übersicht. Namensräume und Klassen sind vom Verzeichnisbaum unabhängig! Mit dem Schlüsselwort using können in C# Namensräume in andere Namensräume importiert werden. Es ist auch möglich, Aliase zu vergeben. Namensräume sind hierarchisch organisiert. Mit using System werden alle öentlichen Typen von System importiert.möchte man eine Klasse innerhalb von System verwenden, so ist diese in Bezug auf System voll anzugeben. Die Basisklassen von.net sind in solchen Namensräumen abgelegt..net Framework 4 and Extensions oder.net Framework 4 Universe veranschaulichen die aktuelle Struktur und Neuerungen. Aufgabe 10.2 Vergleichen Sie die Begrie Namensraum in C# und Package in Java. Arbeiten Sie die Gemeinsamkeiten und die Unterschiede heraus Typsystem von C# Abbildung 10.9: Links: Common Type System, Rechts: value-type und reference-type Betrachtet man das CTS, also die Gesamtzahl aller Typen, so kann man diese für C# wie folgt klassizieren: 81 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

82 10.5 Typsystem von C# Werttypen Enumeration (enum) Strukturen (struct) einfache Typen (sbyte, int, char,... nicht string!) Referenztypen Klassen Felder Schnittstellen Delegate Dies hat jedoch nichts mit der Parameterübergabe byref bzw. byval zu tun. Zwischen den einfachen Typen gibt es die typischen impliziten Konvertierungen. Wir erinnern uns daran, dass alle Typen in C# von object abgeleitet sind. Dies erönet uns zusätzliche Möglichkeiten: Jeder Datentyp kann als Objekt gespeichert oder übergeben werden. Abbildung 10.10: Boxing und Unboxing Der Boxing Vorgang beschreibt die Umwandlung von einem value-type zu einem Objekt. Bei dem Boxing Vorgang wird die Instanz eines Objekts erstellt und der ursprüngliche Wert des value-types wird in das neue Objekt kopiert. Man könnte sagen, dies sei der umgekehrte Vorgang. Beim Unboxing Vorgang wird ein value type aus einem Objekt extrahiert. Der C# Compiler überprüft zusätzlich, ob die von Ihnen angeforderte Variable, welche Sie aus dem Objekt extrahieren wollen, tatsächlich den angeforderten unboxed Type entsprechen kann. Folie veranschaulicht den Vorgang an einem Beispiel. Boxing und Unboxing ist ein zentraler Teil im Type-System von C# (und der Runtime). Es stellt ein Bindeglied zwischen value-types und reference-types zur Verfügung. Value-types haben den Vorteil, dass sie wenig Speicherplatz benötigen. In manchen Fällen ist es jedoch von Vorteil, dass value-types auch die die Eigenschaften von Objekten haben. Diese Übereinkunft macht den Hauptteil von C# aus, daÿ die Verknüpfung zwischen value-types und reference-types dadurch geschieht, dass ein value-type aus einem und in ein Objekt ungewandelt werden kann. Unter dem Motto Es ist zwar alles ein Objekt, aber nur dann wenn es eines sein muss. Quelle: Datentypen Zahlen - Werttypen: Es gibt Werttypen für Zahlen mit verschiedenen Gröÿen und Genauigkeiten. Eine gröÿere Zahl oder eine Zahl mit einer höheren Genauigkeit braucht mehr Speicher auf dem Stack. Jeder Werttyp hat eine Gröÿe. Es ist nicht möglich, einen Wert eines gröÿeren Typs in eine kleinere Variable zu stecken, unabhängig davon, wie groÿ die Zahl tatsächlich ist. 1 c Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010

83 Listings 3.1 C# Grundlagen Operatoren Stringreferenz Stringreferenz Strings - ähnlich Heredoc von PHP StringBuilder zur Verkettung von Strings String auf leer prüfen is/as performant einsetzen Beispiel für Strukturen Generika Listen Enumerationen Enumeration als Flags Trace Schlechter Code Fehler schlucken Indexer Iteratoren Delegaten Delegaten, Beispiel Multicastdelegaten Ereignisse Asynchrone Delegate Benutzerdeniertes Attribute und Reektion Ausdruckslambdas Anweisungslambdas Dispose-Pattern using Attribut Serializable Add-In Add-In nutzen Datenzugri mit DataReader Update mit DataSet LINQ-Beispiele Datenbindung an ein DataGrid Datenbindung in WPF Serverseitige Datenbindung in Asp.Net Ajax-enabled WCF ASP.Net MVC

84 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang C# Event Implementation Fundamentals, Best Practices and Conventions By Jeffrey Schaefer Download source KB Shortened, full article see Terminology and Definitions The literature presenting events and related concepts frequently makes use of multiple words or expressions to describe any given concept. The following list catalogs much of this terminology with brief explanations of the concepts behind the expressions. The term, event, typically means that a change in state of an object has occurred or is about to occur. The term is also used in reference to some activity taking place within an object or application -- activity like the processing of a gesture from an end user (e.g., button clicked), or the reporting of progress during a long-running task. The term, state, refers to the current set of values of one or more variables in an object or application. A change in state means the value of one or more variables within an object has changed. In the event notification process, changes in state, or expected changes in state, are primary motivations for raising events. So, we have two ways to define an event relative to a change in state: immediately prior to a change in state, or immediately after a change in state. While the former are referred to as preevents, the latter are referred to as post-events. event publisher, event source, subject maintain their internal state, and notify other classes (subscribers) through the raising of events or similar notification mechanisms. event subscriber, sink, listener, observer are the classes or objects that are interested in changes in state (or expected changes in state) of the event publishers. Event notifications (frequently expressed as, "fire an event" or "raise an event" or "trigger an event") are generally in the form of the event publisher calling a method in one or more subscribers. Consequently, the raising of an event ultimately means that code in the event publisher causes code in one or more subscribers to run. When an event is raised, the publisher will frequently include data (event data, event-related data, and event arguments ("event args"))that gets sent to the subscribers through the event notification process. This data is presumably relevant to the particular event that was raised, and would be of interest to the event subscribers. For example, an event can be raised when a file gets renamed. Data relevant to that particular "file renamed" event could include (1) the name of the file before the name was changed, and (2) the name of the file after the name was changed. Those file names could comprise the event data that are sent to the subscribers during the raising of the "file renamed" event. To summarize; an "event handler" is the delegate upon which an event is based, while an "event handling method" is a method called in the subscriber when an event is raised. Event handlers are delegates, although delegates are not necessarily event handlers (there are many uses of delegates beyond supporting events). Delegates are presented in more detail later in this article, but only to the extent that they are relevant to events. Events, as implemented in the.net Framework and as described in this article, constitute a.net optimized implementation of the Observer Pattern that was documented by the "Gang of Four" or "GoF" (Gamma et al.1995). C# Event Implementation Fundamentals, Best Practices and Conventions Seite 1 von 10

85 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Delegates In order to understand events, as implemented in.net applications, one must have a clear understanding of the.net delegate type and the role it plays in the implementation of events. Definition and Usage of Delegates Delegates can be understood as intelligent containers that hold references to methods, as opposed to containers that hold references to objects. Delegates can contain references to zero, one, or many methods. In order for a method to be called by a particular delegate instance, that method must be registered with the delegate instance. When registered, the method is added to the delegate's internal collection of method references (the delegate's "invocation list"). Delegates can hold references to static methods or instance methods in any class visible to the delegate instance. Delegate instances can call their referenced methods either synchronously, or asynchronously. When called asynchronously, the methods execute on a separate thread. When a delegate instance is invoked ("called"), then all methods referenced by the delegate are called automatically by the delegate. Delegates cannot contain references to just any method. Delegates can hold references only to methods defined with a method signature that exactly matches the signature of the delegate. Consider the following delegate declaration: public delegate void MyDelegate(string mystring); Notice that the delegate declaration looks like a method declaration, but with no method body. The signature of the delegate determines the signature of methods that can be referenced by the delegate. So, the sample delegate above (MyDelegate) can hold references only to methods that return void while accepting a single string argument. Consequently, the following method can be registered with an instance of MyDelegate: private void MyMethod(string somestring) // method body here. The following methods, however, cannot be referenced by a MyDelegate instance because their signatures do not match that of MyDelegate. private string MyOtherMethod(string somestring) // method body here. private void YetAnotherMethod(string somestring, int someint) // method body here. After a new delegate type is declared, an instance of that delegate must be created so that methods can be registered with, and ultimately invoked by, the delegate instance. // instantiate the delegate and register a method with the new instance. C# Event Implementation Fundamentals, Best Practices and Conventions Seite 2 von 10

86 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang MyDelegate del = new MyDelegate(MyMethod); After a delegate is instantiated, additional methods can be registered with the delegate instance, like this: del += new MyDelegate(MyOtherMethod); At this point, the delegate can be invoked, like this: del("my string value"); And, because both MyMethod and MyOtherMethod are registered with the MyDelegate instance (named del), that instance will invoke both MyMethod and MyOtherMethod when the above line executes, passing each the string value, "my string value." Delegates and Overloaded Methods In the case of an overloaded method, only the particular overload having a signature that exactly matches the signature of the delegate can be referenced by (or registered with) the delegate. When you write code that registers an overloaded method with a delegate instance, the C# compiler will automatically select and register the particular overload with a matching signature. So, for example, if your application declared the following delegate type... public delegate int MyOtherDelegate(); // returns int, no parameters... and you registered an overloaded method named MyOverloadedMethod with an instance of MyOtherDelegate, like this... anotherdel += new MyOtherDelegate(MyOverloadedMethod);... the C# compiler will register only the particular overload with a matching signature. Of the following two overloads, only the first would be registered with the anotherdel instance of the MyOtherDelegate type: // requires no parameters - so can be registered with a MyOtherDelegate // instance. private int MyOverloadedMethod() // method body here. // requires a string parameter - so cannot be registered with a MyOtherDelegate instance. private int MyOverloadedMethod(string somestring) // method body here. A single delegate cannot selectively register or call both (multiple) overloads. If you need to call both (multiple) overloads, then you would need additional delegate types -- one delegate C# Event Implementation Fundamentals, Best Practices and Conventions Seite 3 von 10

87 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang type per signature. Your application-specific logic would then determine which delegate to invoke, and therefore which overload is called (by the delegate with the corresponding signature). Why Delegates? If this is your first introduction to delegates, you may be wondering, "Why bother? It's just simpler to call the method directly -- so what is the benefit of going through a delegate?" Necessary Indirection A brief answer (to the "why bother?" question above) is that the code we write or components we use cannot always "know" which specific method to call at a particular point in time. So, one important perspective of delegates is that they provide a way for.net components to call your code -- without the.net component having to know anything about your code beyond the method signature (as mandated by the delegate type). For example,.net Framework components, like the Timer component, frequently need to execute code that you write. Because the Timer component cannot possibly know which specific method to call, it specifies a delegate type (and therefore signature of a method) to be invoked. Then you connect your method -- with the requisite signature -- to the Timer component by registering your method with a delegate instance of the delegate type expected by the Timer component. The Timer component can then run your code by invoking the delegate which, in turn, calls your method. Note that the Timer component still knows nothing about your specific method. All the Timer component knows about is the delegate. The delegate, in turn, knows about your method because you registered your method with that delegate. The end result is that the Timer component causes your method to run, but without knowing anything about your specific method. Just like the Timer component example above, we can make use of delegates in a way that enables us to write our code without our code having to "know" the specific method that will ultimately be called at a specific point. Rather than calling a method at that point, our code can invoke a delegate instance which, in turn, calls any methods that are registered with the delegate instance. The end result is that a compatible method is called even though the specific method to be called was not written directly into our code. Synchronous and Asynchronous Method Invocation All delegates inherently provide for both synchronous and asynchronous method invocation. So, another common reason to call methods via delegate instances is to invoke methods asynchronously -- in which case the called method runs on a separate thread pool thread. Event Foundation As you'll see later in this article, delegates play an integral role in the implementation of events in the.net Framework. In brief, delegates provide a necessary layer of indirection between event publishers and their subscribers. This indirection is necessary in order to maintain a clean separation between the publisher and subscriber(s) meaning that subscribers can be added and removed without the publisher needing to be modified in any way. In the case of event publication, the use of a delegate makes it possible for an event C# Event Implementation Fundamentals, Best Practices and Conventions Seite 4 von 10

88 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang publisher to know nothing about any of its subscribers while still broadcasting events and associated event data to any/all subscribers. Delegate Internals Declaring a Delegate Results in A New Class Being Created A delegate declaration that you write is sufficient to define an entire and new delegate class. The C# compiler takes your delegate declaration and inserts a new delegate class in the output assembly. The name of that new class is the name of the delegate type you supply in your delegate declaration. The signature you specify in your delegate declaration becomes the signature of the methods in the new class used to call any/all of the delegate's referenced methods (specifically the Invoke and BeginInvoke methods). This new class extends (inherits) System.MulticastDelegate. So most of the methods and properties available in your new delegate class come from System.MulticastDelegate. The Invoke, BeginInvoke, and EndInvoke methods are inserted by the C# compiler when it creates the new class in the output assembly (these are the methods you can call to cause the delegate to invoke any/all referenced methods -- Invoke for synchronous invocation, and BeginInvoke and EndInvoke used in asynchronous invocations). The new class created from your delegate declaration can be understood as being a completed and full-blown MulticastDelegate implementation that has the type name you supplied in your delegate declaration, and is capable of calling methods with the specific signature that you also supplied in your delegate declaration. As an example, when the C# compiler encounters the following delegate declaration... public delegate string MyFabulousDelegate(int myintparm);... the compiler inserts a new class named MyFabulousDelegate into the output assembly. The Invoke, BeginInvoke, and EndInvoke methods of the MyFabulousDelegate class include the int parameter and returned string value in their respective method signatures. It should be noted that MulticastDelegate is a special class in that compilers can derive from it, but you cannot derive from it explicitly. Your use of the C# delegate keyword and associated syntax is how you instruct the C# compiler to extend MulticastDelegate for your purposes. Meaning of Multicast The meaning of "multicast" in System.MulticastDelegate is that the delegate is capable of holding references to multiple methods -- not just one method. In the case of delegate instances that hold references to multiple methods, all referenced methods are called when the delegate instance is invoked. Finally, C and C++ programmers will recognize that delegates are similar to C-style function pointers. An important difference, though, is that a delegate is not simply a pointer to a raw memory address. Instead, delegate instances are type-safe objects that are managed by the.net CLR and that specifically reference one or more "methods" (as opposed to memory addresses. C# Event Implementation Fundamentals, Best Practices and Conventions Seite 5 von 10

89 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang The Relationship Between Delegates and Events Events in.net programming are based on delegates. Specifically, an event can be understood as providing a conceptual wrapper around a particular delegate. The event then controls access to that underlying delegate. When a client subscribes to an event, the event ultimately registers the subscribing method with the underlying delegate. Then, when the event is raised, the underlying delegate invokes each method that is registered with it (the delegate). In the context of events, then, delegates act as intermediaries between the code that raises events and the code that executes in response thereby decoupling event publishers from their subscribers. Events do not, by themselves, maintain a list of subscribers. Instead, events control access to some underlying list of subscribers and that list is typically implemented as a delegate (although other list-type objects or collections can serve in place of a delegate). Event Handlers (in general) A delegate that exists in support of an event is referred to as an "event handler". To be clear, an "event handler" is a delegate, although delegates are frequently not event handlers. This article uses the expression, "event handler," only in reference to the delegate, while using the expression, "event handling method," in reference to any method registered with the delegate. Custom Event Handlers You can define your own event handlers (delegates), or you can use one of the event handlers provided by the.net Framework (i.e., System.EventHandler, or the generic System.EventHandler<TEventArgs>). The following sample event declaration make use of a custom event handler rather than using a Framework-provided event handler. Consider the following: Line 1: public delegate void MyDelegate(string whathappened); Line 2: public event MyDelegate MyEvent; Line 1 declares a delegate type for which any method can be assigned -- provided that the method returns void and accepts a single string argument. Line 2 declares an event in terms of the delegate type. Notice that the event (which is named MyEvent) is declared very much like a method declaration -- but with its data type specified as the delegate type: public scope specifying that objects outside of our class can subscribe to the event. event keyword used to define the event. MyDelegate data type of the event (this is the custom delegate type defined in Line 1.) MyEvent name of the event. The delegate declared in Line 1 is just an ordinary delegate (as are all delegates), and can be used for any purpose delegates can fulfill. Line 2 (i.e., the usage of the delegate type) is what turns that delegate into an event handler. In order to communicate that a particular delegate C# Event Implementation Fundamentals, Best Practices and Conventions Seite 6 von 10

90 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang type is being used as an event handler, a naming convention has emerged whereby the delegate type name ends with "Handler" (more on this later). Standardized Event Handlers While you can create your own event handlers (and sometimes you might need to), you should use one of the EventHandler delegates provided by the.net Framework in cases where one of the Framework's event handlers would work with your particular event implementation. Many events make use of event handlers that can have common or identical signatures. So, rather than clutter your source code with many delegates that differ only by type name, you can/should make use of the built-in event handlers, as doing so reduces the amount of code you would need to write and maintain, and makes your code more easily understood. If someone reading your code sees you are basing an event on the System.EventHandler delegate, for example, then they automatically know a lot about your event implementation without having to look further. The Generic System.EventHandler<TEventArgs> Delegate The declaration of this built-in delegate enforces the constraint that the type, TEventArgs, be of type System.EventArgs (including, of course, subclasses thereof): public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs; Now suppose you want to strongly type the sender, rather than having it typed as object. You can leverage generics to create your own generic event handler: public delegate void MyGenericEventHandler<T, U>(T sender, U u) where U : EventArgs; You can then use this custom generic event handler to additionally specify a type-safe sender parameter (i.e., thereby limiting the type of object that can be communicated as having raised the event): public event MyGenericEventHandler<MyPublisher, MyEventArgs> MyEvent; The intent here would be that this event will only be raised by objects of type MyPublisher. Subscribers to the event would therefore be able to subscribe only to events published by the MyPublisher class. Event Arguments (EventArgs) Event arguments -- sometimes referred to as "event args" -- constitute the data sent by the publisher of an event to the subscribers during the raising of the event. Presumably this data is relevant to the occurrence of the event. For example, when a "file was just renamed" event is raised, the event arguments would likely include the name of the file before the name change, as well as the name of the file after the name was changed. The event handling methods can read the event arguments (referred to as "event data") to learn more about the event occurrence. C# Event Implementation Fundamentals, Best Practices and Conventions Seite 7 von 10

91 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang The Role of System.EventArgs You have two basic alternatives for including event arguments with your events. 1. You can encapsulate all event arguments as properties of a class that derives from System.EventArgs. At runtime, an instance of that class is then sent to the event subscribers when the event is raised. The event subscribers read the event arguments as properties of that class. 2. You can avoid the use of System.EventArgs and, instead, declare individual event arguments -- much as you would include arguments in a method declaration. This approach is discouraged. The first alternative listed above is strongly encouraged, and support for it is built into the.net Framework through the System.EventArgs class. Events implemented in.net Framework components, by convention, provide their event arguments as instances System.EventArgs, or as event-specific subclasses of System.EventArgs. Some events carry no data. In these cases, System.EventArgs is used as a placeholder, primarily for purposes of keeping one consistent event handler signature across all events regardless of whether the events carry data or carry no data. In cases of events with no data, the event publisher sends the value, System.EventArgs.Empty, during the raising of the event. Event Declaration Syntax Event Declaration Syntax Alternatives The event keyword is used to formally declare an event. The C# compiler will translate the declaration into the following three components in the output assembly. 1. Privately scoped event handler (or a functionally equivalent data structure). The delegate is privately scoped in order to prevent external code from invoking the event, and thereby preserving encapsulation. 2. publicly scoped Add method; used to add subscribers to the private event handler. 3. publicly scoped Remove method used to remove subscribers from the private event handler. Field-like syntax: public event TheEventHandler MyEvent; The field-like syntax declares the event in one or two lines of code (one line for the event, another for the asso ciated event handler -- if/when not using a built-in EventHandler delegate). Alternatively, there exists a property-like syntax (details see full article). Event Raising Code For each event, the publisher should include a protected virtual method that is responsible for raising the event. This will allow subclasses to [more] easily access base class events. Of course the recommendation to make this method protected and virtual applies only to non static events in unsealed classes. protected virtual void OnMailArrived(MailArrivedEventArgs) C# Event Implementation Fundamentals, Best Practices and Conventions Seite 8 von 10

92 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang // Raise event here Once an event and any associated delegate and publishing method have been defined, the publisher will need to raise the event. Raising the event should generally be a two step process. The first step would be to check to see if there are any subscribers. The second step is to raise the event, but only if there are any subscribers. Any unhandled exceptions raised in the event handling methods in subscribers will be propagated to the event publisher. The raising of the event should therefore be attempted only within a try/catch block: public void RaiseTheEvent(MyEventArgs eventargs) try MyEventHandler handler = MyEvent; if (handler!= null) handler (this, eventargs) catch // Handle exceptions here Events can have multiple subscribers each of which is called, in turn, by the event handler (delegate) when the event handler is invoked by the [handler (this, eventargs)] line. The event handler used in the above block of code would stop iterating over it's invocation list (of subscribed event handling methods) when the first unhandled exception is raised by a subscriber. So, if there were 3 subscribers, for example, and the 2nd one threw an unhandled exception when invoked by the delegate, then the 3rd subscriber would never receive the event notification. If you want for every subscriber to receive the event notification even if other subscribers throw unhandled exceptions, then you could use the following logic which explicitly loops through the event handler's invocation list: public void RaiseTheEvent(MyEventArgs eventargs) MyEventHandler handler = MyEvent; if (handler!= null) Delegate[] eventhandlers = handler.getinvocationlist(); foreach (Delegate currenthandler in eventhandlers) MyEventHandler currentsubscriber = (MyEventHandler)currentHandler; try currentsubscriber(this, eventargs); catch (Exception ex) // Handle exception here. C# Event Implementation Fundamentals, Best Practices and Conventions Seite 9 von 10

93 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Event Subscriber Registration and Unregistration By design, the publisher of an event has absolutely no knowledge of any of the subscribers. Consequently, it is the job of subscribers to register or unregister themselves with the publisher of an event. Registering A Subscriber In order to subscribe to an event, the subscriber needs three things: 1. a reference to the object publishing the event of interest 2. an instance of the delegate upon which the event is defined 3. a method that will be called by the publisher when it raises the event The subscriber then registers its event handler (delegate) instance with the publisher, like this: thepublisher.eventname += new MyEventHandlerDelegate(EventHandlingMethodName); In the above line... thepublisher is the reference to the object that will raise the event of interest. Notice how the event, EventName, is accessed as if it were a public property of thepublisher. The += operator is used to add the delegate instance to the invocation list of the event handler in the publisher. Remember, multiple subscribers may register with the event. Use the += operator to append the current subscriber to the underlying delegate's invocation list. MyEventHandlerDelegate is a reference the particular event hander delegate to be used (if not one of the built-in EventHandler delegates). Finally EventHandlingMethodName supplies the name of the method in the subscribing class that is to be called upon the raising of the event. WARNING: Do not use the = operator when registering an event subscriber with a publisher. Doing so would replace any/all currently registered event subscribers with the current subscriber. Instead, be sure to use the += operator to cause the current subscriber to be appended to the event handler's invocation list. Unregistering A Subscriber A subscriber can unregister from the publisher, like this: thepublisher.eventname -= EventHandlerDelegate(EventHandlingMethodName); The -= operator is used to remove the delegate instance from the invocation list in the publisher. Subscribers are automatically unregistered when an object is disposed if the subscriber was not already explicitly unregistered from the event. C# Event Implementation Fundamentals, Best Practices and Conventions Seite 10 von 10

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Understanding Routed Events and Commands In WPF Brian Noyes, September One of the most daunting things about getting up to speed on Windows Presentation Foundation (WPF) is that there are so many new constructs to master. Even simple things like Microsoft.NET Framework properties and events have new counterparts in WPF with added capabilities and associated complexity specifically dependency properties and routed events. Then there is all the brand new stuff, such as animations, styling, control templates, and routed commands. There is a lot to learn. In this article I am going to focus on two very important items in the list of new WPF elements to master. These items routed events and routed commands are related to each other. They form the basis for communication among the various parts of your user interface whether those parts are individual controls on one big Window class or whether they are controls and their supporting code in separate, decoupled parts of your user interface. For this article I am assuming you are already familiar with the fundamentals of WPF, such as how to construct a UI using built-in WPF controls and declaring the layout of your UI in XAML. Routed Events Overview When you are first getting started with WPF, you will likely use routed events without even knowing you are using them. For example, if you add a button to your window in the Visual Studio designer and name it mybutton and then double-click on it, the Click event will get hooked up in your XAML markup and an event handler for the Click event will be added to the codebehind of your Window class. This should feel no different than hooking up events in Windows Forms and ASP.NET. It is actually a little closer to the coding model for ASP.NET but more like the runtime model of Windows Forms. Specifically, in your XAML markup for the button, you end up with code like this: <Button Name="myButton" Click="myButton_Click">Click Me</Button> The XAML declaration for hooking up an event looks just like a property assignment in XAML but results in a normal event hookup on the object that specified the event handler. This hookup actually happens in a compile-time-generated partial class for your window. To see this, go to the constructor for your class, right-click on the InitializeComponent method call, and select Go To Definition from the context menu. The editor will display a generated code file (with a naming convention of.i.g.cs or.i.g.vb) containing the code that is normally generated at compile time. Scroll down in the displayed partial class to the Connect method where you will see the following: #line 6 "..\..\Window1.xaml" this.mybutton.click += new System.Windows.RoutedEventHandler( this.mybutton_click); This partial class is generated from the XAML at compile time and contains those elements of the XAML that need design-time compilation. Most of your XAML ends up as a binaryembedded resource in your compiled assembly and is merged at run time with the compiled code from the binary representation of your markup. If you take a look at the codebehind for the window, the Click handler looks like this: private void mybutton_click( object sender, RoutedEventArgs e) So far this looks like any other.net event hookup you have an explicitly declared delegate hooked up to an event on an object, and the delegate points to a handling method. The only thing to tip you off that you are using routed events is the type of the event argument for the Understanding Routed Events and Commands In WPF Seite 1 von 12

111 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Click event, which is RoutedEventArgs. What is so special about routed events then? To understand that, you first need to understand the elemental composition model of WPF. WPF Element Trees If you start with a new window in a project and drag a button onto the window in the designer, you end up with an element tree in the XAML that looks like this (attributes omitted for clarity): <Window> <Grid> <Button/> </Grid> </Window> Each of these elements represents a runtime instance of a corresponding.net type, and the declared hierarchy of elements forms what is called the logical tree. In addition, many controls in WPF are either ContentControls or ItemsControls, meaning they can have child elements. For example, a Button is a ContentControl, and it can have a complex child element as its content. You could expand the logical tree, as you see here: <Window> <Grid> <Button> <StackPanel> <Image/> <TextBlock/> </StackPanel> </Button> </Grid> </Window> This results in a UI like that shown in Figure 1. Figure 1 Simple Window with Button Content As you can imagine, the tree could start to take on multiple branches (another Button in the Grid), and the logical tree can grow significantly in complexity. The thing to realize about WPF elements in the logical tree is that what you see is not really what you get at run time. Each of those elements usually expands to a more complicated tree of visual elements at run time. In this example, the logical tree of elements expands to the visual tree of elements shown in Figure 2. Figure 2 Simple Window Visual Tree I used a tool called Snoop (blois.us/snoop) to see the elements of the visual tree shown in Figure 2. You can see that the window (EventsWindow) actually wraps its content in a Border and an Adorner- Decorator and presents the content inside of that with a ContentPresenter. The button does something similar, wrapping its content in a ButtonChrome object and presenting the content with a ContentPresenter. When I click on my button, I may not actually be clicking on the Button element at all; I may be clicking on a child element in the visual tree, possibly even one that is not shown in my logical tree (such as the ButtonChrome). For example, say that I click the mouse on top of the image inside my button. The click really manifests itself initially as a MouseLeftButtonDown event inside the Image element. But somehow that needs to get translated into a Click event at the Button level. This is where the routing in routed events comes in. Understanding Routed Events and Commands In WPF Seite 2 von 12

112 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Event Routing Understanding a little about the logical and visual trees is important because routed events get routed based primarily on the visual tree. Routed events support a RoutingStrategy of Bubble, Tunnel, or Direct. Bubble is the most common and means that an event will bubble (propagate) up the visual tree from the source element until either it has been handled or it reaches the root element. This allows you to handle an event on an object further up the element hierarchy from the source element. For example, you could attach a Button.Click handler on the enclosing Grid element instead of directly on the button itself. Bubble events just have names that indicate their action (for example, MouseDown). Tunnel events go in the other direction, starting at the root element and traversing down the element tree until they are handled or reach the source element for the event. This allows upstream elements to intercept the event and handle it before the event reaches the source element. Tunnel events have their names prefixed with Preview by convention (such as PreviewMouseDown). Direct events behave like normal events in the.net Framework. The only potential handler for the event is a delegate that is hooked up to the event. Usually if a Tunnel event is defined for a particular event, there is a corresponding Bubble event. In that case, the Tunnel event fires first, starting at the root and working its way down to the source element looking for a handler. Once it has been handled or has reached the source element, the Bubble event is fired, working its way up from the source element and looking for a handler. A Bubble or Tunnel event does not stop its routing just because an event handler is called. If you want to stop the bubbling or tunneling process, you mark the event as handled in your event handler using the event arguments you are passed: private void OnChildElementMouseDown(object sender, MouseButtonEventArgs e) e.handled = true; Once your handler marks an event as handled, it will not be raised to any more handlers. Well, that is only partially true. In reality, event routing continues behind the scenes, and you can explicitly hook up event handlers in code with an override of the UIElement.AddHandler method that has an additional flag to effectively say, "Call me even if the event has been marked as handled." You specify that flag with a call like the following: m_somechildelement.addhandler(uielement.mousedownevent, (RoutedEventHandler)OnMouseDownCallMeAlways,true); The first parameter to AddHandler is the RoutedEvent you want to handle. The second is a delegate to the event-handling method (which will need to have the correct signature for the event's delegate). The third parameter indicates whether you want to be notified even if another handler has marked the event as handled. The element on which you call AddHandler is the one that will be watching for the event to flow by during routing. Routed Events and Composition Let's walk through how the Button.Click event comes into being to drive home why all this is important. As I mentioned before, a user will initiate a Click event with a MouseLeftButtonDown event on some child element in the visual tree of your Button, such as the Image in the previous example. When the MouseLeftButtonDown event happens inside the Image element, a PreviewMouseLeftButtonDown event starts at the root and tunnels down to the Image. If no handlers set the Handled flag to true for the preview event, the MouseLeftButtonDown event then starts bubbling up from the Image element until it gets to the Button. The button handles that event, sets the Handled flag to true, and raises its own Click event. The sample code for this article includes an application with handlers hooked up throughout the routing chain to help you visualize this process. Understanding Routed Events and Commands In WPF Seite 3 von 12

113 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang The implications are quite powerful. For example, if I choose to replace the default button appearance by applying a control template that contains an Ellipse element, I don't have to do anything to ensure that clicks outside the Ellipse don't fire the Click event. Clicks just outside the edge of the Ellipse will still be inside the rectangular bounds of my button, but Ellipse has its own hit detection for MouseLeftButtonDown, and the empty portions of the button outside the Ellipse do not. So only clicks inside the Ellipse raise the MouseLeftButtonDown event. It is still handled by the Button class to which the template is attached, so you will get predictable behavior from even your customized button. This is also an extremely important concept to remember when writing your own custom composite controls because you will likely need to do things similar to what Button is doing to handle events from the child elements that get placed inside your control. Attached Events In order to enable elements to handle events that are declared in a different element, WPF supports something called attached events. Attached events are routed events that support a hookup in XAML on elements other than the type on which the event is declared. For example, if you want the Grid element to listen for a Button.Click event to bubble past, you would simply hook it up like the following: <Grid Button.Click="myButton_Click"> <Button Name="myButton" >Click Me</Button> </Grid> The resulting code in the compile-time-generated partial class now looks like this: #line 5 "..\..\Window1.xaml" ((System.Windows.Controls.Grid)(target)).AddHandler( System.Windows.Control s.primitives.buttonbase.clickevent, new System.Windows.RoutedEventHandler(this.myButton_Click)); Attached events simply give you a little more flexibility in where you hook up your event handlers. But if the elements are contained in the same class (as in this example), it may not be apparent what difference it makes because, in either case, the handling method is still just a method on the Window class. It matters in two ways. First, event handlers are called based on where the handling element is in the bubbling or tunneling element chain. Second, this lets you do something like handle events from objects that may be encapsulated down inside a control you are using. For example, you could handle Button.Click events like those shown on the Grid, but those Button.Click events could be bubbling out from inside of a user control contained in your window. Not all events are declared as attached events. In fact, most are not. But attached events can be quite handy when you need to do event handling somewhere else besides the control's source. Routed Commands Overview Now that you have seen routed events, you are ready to understand routed commands. WPFrouted commands give you a specific mechanism for hooking up UI controls such as toolbar buttons and menu items to handlers without introducing a lot of tight coupling and repetitive code into your application. Routed commands give you three main things on top of normal event handling: Routed command source elements (invokers) can be decoupled from command targets (handlers) they do not need direct references to one another, as they would if they were linked by an event handler. Routed commands will automatically enable or disable all associated UI controls when the handler indicates the command is disabled. Understanding Routed Events and Commands In WPF Seite 4 von 12

114 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Routed commands allow you to associate keyboard shortcuts and other forms of input gestures (ink gestures, for example) as another way to invoke the command. In addition, a specific flavor of routed command, the RoutedUICommand class, adds the ability to define a single Text property to be used for the text prompting of any controls that are invokers for the command. The Text property can also be localized more easily than visiting each associated invoker control. To declare a command on an invoker, you simply set a Command property on the control that will fire the command: <Button Command="ApplicationCommands.Save">Save</Button> The Command property is supported by MenuItem, Button, RadioButton, CheckBox, Hyperlink, and a number of other controls. For an element that you want to act as a command handler, you set up a CommandBinding: <UserControl...> <UserControl.CommandBindings> <CommandBinding Command="ApplicationCommands.Save" CanExecute="OnCanExecute" Executed="OnExecute"/> </UserControl.CommandBindings>... </UserControl> The CanExecute and Executed properties of a command binding point to methods in the codebehind of the declaring class that are called during the command-handling process. The important thing here is that the command invoker does not need any knowledge of or reference to the command handlers, and a handler does not have to know what element is going to invoke the command. CanExecute is called to determine whether or not the command should be enabled. To enable the command, set the CanExecute property of the event arguments to true, as shown here: private void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) e.canexecute = true; A command is also enabled if there is a command handler with a defined Executed method but no CanExecute method (CanExecute is implicitly true in that case). The Executed method is where you take whatever action is appropriate based on that command being invoked. This may be saving a document, submitting an order, sending an , or some other action with which the command is associated. Routed Command in Action To make this more concrete and to quickly see the benefits of routed commands, let's look at a simple example. In Figure 3 you see a simple UI with two input textboxes and a toolbar button for performing a Cut action on the text in the textboxes. Figure 3 Simple App with Cut Command Toolbar Button To get this hooked up using events, you would need to define a Click handler for the toolbar button, and that code would need references to the two textboxes. You would have to determine which textbox has the focus and call appropriate clipboard operations based on the text selection in the control. You would also have to worry about enabling and disabling the toolbar button at appropriate times based on where the focus is and whether anything was selected in the textbox. Ugly, messy, tightly coupled code. It doesn't sound too bad for this simple form, but what if those textboxes are now down inside a user control or a custom control and your window codebehind doesn't have direct access to them? You would either have to expose an API at your user control boundary to make Understanding Routed Events and Commands In WPF Seite 5 von 12

115 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang hooking things up from the container possible or expose the textboxes publicly neither approach is ideal. With commands, all you need to do is set the Command property on the toolbar button to the Cut command that is defined in WPF and you are done: <ToolBar DockPanel.Dock="Top" Height="25"> <Button Command="ApplicationCommands.Cut"> <Image Source="cut.png"/> </Button> </ToolBar> You could now run the app and see that the toolbar button is initially disabled. After you select some text in one of the textboxes, the toolbar button becomes enabled and, if you click it, the text is actually cut to the clipboard. And it would work for any textbox anywhere in your UI. Wow pretty cool, huh? What is happening here is that the TextBox class implementation has a built-in command binding for the Cut command and encapsulates the clipboard handling for that command (and Copy and Paste as well) for you. So how does the command only get invoked on the in-focus textbox, and how does the message get to the textbox to tell it to handle the command? That is where the routed part of routed commands comes into play. Command Routing The difference between routed commands and routed events is in how the command gets routed from the command invoker to the command handler. Specifically, routed events are used under the covers to route messages between the command invokers and the command handlers (through the command binding that hooks it into the visual tree). There could be a many-to-many relationship here, but only one command handler will actually be active at any given time. The active command handler is determined by a combination of where the command invoker and command handler are in the visual tree, and where the focus is in the UI. Routed events are used to call the active command handler to ask whether the command should be enabled, as well as to invoke the command handler's Executed method handler. Usually, a command invoker looks for a command binding between its own location in the visual tree and the root of the visual tree. If it finds one, the bound command handler will determine whether the command is enabled and will be called when the command is invoked. If the command is hooked up to a control inside a toolbar or menu (or, more generally, a container that sets FocusManager.IsFocusScope = true), then some additional logic runs that also looks along the visual tree path from the root to the focus element for a command binding. In the simple application from Figure 3, what happens is this: because the Cut command button is in a toolbar, CanExecute and Execute are handled by the TextBox instance that has the focus. If the textboxes in Figure 3 were contained within a user control, then you would have an opportunity to set up a command binding on the window, the user control that contains the Grid, the Grid that contains the textboxes, or on the individual textboxes. Whichever textbox has the focus will determine the end of the focus path originating from the root. An important thing to understand about the routing of WPF routed commands is that once a single command handler is invoked, then no other handlers will be called. So if the user control handles the CanExecute method, the TextBox CanExecute implementation will no longer be called. Defining Commands Both the ApplicationCommands.Save and the ApplicationCommands.Cut commands are two of many commands provided by WPF. The five built-in command classes in WPF along with some examples of the commands they contain are shown in Figure 4. Figure 4 WPF Command Classes Understanding Routed Events and Commands In WPF Seite 6 von 12

116 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Command Class Example Commands ApplicationCommands Close, Cut, Copy, Paste, Save, Print NavigationCommands BrowseForward, BrowseBack, Zoom, Search EditingCommands AlignXXX, MoveXXX, SelectXXX MediaCommands Play, Pause, NextTrack, IncreaseVolume, Record, Stop ComponentCommands MoveXXX, SelectXXX, ScrollXXX, ExtendSelectionXXX The XXX indicates a collection of operations such as MoveNext and MovePrevious. The commands in each class are defined as public static (Shared in Visual Basic ) properties so that you can easily hook them up. You can define your own custom commands easily by following the same approach. I'll show an example of this a little later. You can also use these commands with a shorthand notation, like the following: <Button Command="Save">Save</Button> When you use this shortened version, a type converter in WPF will try to locate the named command against the collection of built-in commands. The net result in this case is exactly the same. I prefer to use the long-named versions to make the code more explicit and maintainable. Then there is no ambiguity as to where that command is defined. Even the builtin commands have some duplication between the EditingCommands and ComponentCommands classes. Command Plumbing Routed commands are a specific implementation of the ICommand interface defined by WPF. ICommand has the following definition: public interface ICommand event EventHandler CanExecuteChanged; bool CanExecute(object parameter); void Execute(object parameter); The built-in WPF command types are RoutedCommand and RoutedUICommand. Both of these classes implement the ICommand interface and use routed events I described earlier to do the routing. A command invoker is expected to call CanExecute to determine whether to enable or disable any associated command invocation code. The command invoker can determine when to invoke that method by subscribing to the CanExecuteChanged event. In the RoutedCommand class, CanExecuteChanged is fired based on changes of state or focus in the UI. When the command is invoked, the Executed method is called and gets dispatched to the handler through a routed event along the visual tree. Classes that support the Command property, such as the ButtonBase class, implement the ICommandSource interface: public interface ICommandSource ICommand Command get; object CommandParameter get; IInputElement CommandTarget get; The Command property associates the invoker with the command it will invoke. CommandParameter allows the invoker to pass some data along with the invocation of the command. The CommandTarget property lets you override the default routing based on the focus path and tell the commanding system to use the specified element as the handler of the command, instead of leaving it up to the routed event and focus-based determination of the command handler. Routed Command Challenges Routed commands work nicely for simple user interface scenarios, hooking up toolbar and menu items, and handling those things that are inherently coupled to the keyboard focus (such as clipboard operations). Where routed commands are insufficient, however, is when you start building complex user interfaces, where your command handling logic is in supportng code for your view definitions and your command invokers are not always inside of a toolbar or Understanding Routed Events and Commands In WPF Seite 7 von 12

117 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang menu. This often comes up when using UI composition patterns such as Model View Controller, or MVC (msdn.microsoft.com/magazine/cc337884), Model View Presenter, or MVP (msdn.microsoft.com/magazine/cc188690), or Presentation Model, which is also known as Model View ViewModel in WPF circles (msdn.microsoft.com/library/cc707885). The problem when you get into that arena is that the enabling and handling logic for a command may not be part of the visual tree directly; rather, it may be located in a presenter or presentation model. Additionally, the state that determines whether the command should be enabled may have no relation to where the command invokers and views are in the visual tree. You may also have scenarios where more than one handler is valid at a given time for a particular command. To see where you might get yourself in trouble with routed commands, take a look at Figure 5. It is a simple window that contains a couple of user controls that represent views in an MVP or MVC pattern. The main window contains a File menu and toolbar with Save command buttons in them. The main window also has an input textbox at the top of the window, along with a Button that has its Command set to the Save command. Figure 5 Composite User Interface (Click the image for a larger view) Tip: Hooking Up Anonymous Methods In the code in Figure 6 I use a trick learned from my colleague Juval Lowy hooking up an empty anonymous method to the delegate in its declaration: Action<string> m_executetargets = delegate ; By doing so, you never have to check for null before invoking the delegate because there will always be one no-op subscriber in its invocation list. You also avoid a potential race condition with unsubscribing in a multithreaded environment if you were doing null checking instead. For more details on that trick, see Programming.NET Components, Second Edition, by Juval Lowy. The rest of the UI is provided by two views, and each is an instance of a simple user control. The border color has been set differently for each user control instance in order to make it easy to see what portion of the UI they provide. Each of the user control instances has a Save button that has its Command property set to the Save command. The challenge introduced by routed commands being tied to a location in the visual tree becomes apparent in this simple example. In Figure 5, the window itself does not have a CommandBinding for the Save command. However, it does contain two invokers (the menu and toolbar) for that command. In this situation, I don't want the top-level window to have to know what to do when the command is invoked. I want to leave it up to the child views, represented by the user controls, to handle the command. The user control class in this example has a CommandBinding for the Save command, and that CommandBinding returns true for CanExecute. Understanding Routed Events and Commands In WPF Seite 8 von 12

118 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang However, in Figure 5 you can see that while the focus is at the window level in the textbox at the top, the command invokers at this level are disabled. Also, the Save buttons in the user controls are enabled even though the focus is not yet inside the user control. If you change the focus to one of the textboxes inside one of the user control instances, then the command invokers in the menu and toolbar become enabled. But the Save button in the window itself does not become enabled. In fact, in this case there is no way to get the Save button next to the textbox at the top of the window to enable with normal routing. The reason again has to do with the location of the individual controls. With no command handlers at the window level, while the focus is outside of the user controls, there is no command handler up the visual tree or on the focus path to enable the controls that are hooked up as command invokers. The command is therefore disabled by default as far as those controls are concerned. However, for the command invokers inside the user controls, the command is enabled because the handler is up the visual tree from them. Once you switch the focus to a textbox inside one of the user controls, the user control, which is between the window and the textbox on the focus path, provides the command handler that enables the command for the toolbar and menu, because they check the focus path as well as the path from their location in the visual tree to the root. And there is no way to enable the button at the window level because it will never have a handler between it and the root. If trying to follow all that visual tree and focus-path mumbo jumbo made your head hurt for this simple little example, imagine what you will have to go through to reason out command enabling and invoking for a seriously complicated UI with command invokers and handlers in many different locations in the visual tree. Let's just say the movie Scanners and exploding heads come to mind. Avoiding Command Problems To avoid the potential visual tree location problems with routed commands, you'll need to keep things simple. You will generally need to make sure your command handlers are on the same element or further up the visual tree from the element that will invoke the command. One way to do this is to inject a command binding at the window level by using the CommandManager.RegisterClassCommandBinding method from the control contributing a command handler. The exception to this is if you implement a custom control that itself accepts keyboard focus (like a textbox). In that case, if you want to embed command handling on the control itself and that command handling is only relevant when the focus is on your control, then you can do so and it will work out just like the Cut command example shown earlier. You can also overcome focus issues by explicitly specifying a command handler through the CommandTarget property. For example, for the window-level Save button that was never enabled in Figure 5, you could change its command hookup to the following: <Button Command="Save" CommandTarget="Binding ElementName=uc1" Width="75" Height="25">Save</Button> In this code, the Button specifically sets its CommandTarget to a UIElement instance that has a command handler in it. In this case, it is specifying the element named uc1, which happens to be one of the two user control instances in the example. Because that element has a command handler that always returns CanExecute = true, the Save button at the window level becomes always enabled and will only call that control's command handler, regardless of where the invoker is relative to the command handler. Going beyond Routed Commands As a result of the limitations of routed commands, a number of companies building complex UIs with WPF have started using custom ICommand implementations that allow them to Understanding Routed Events and Commands In WPF Seite 9 von 12

119 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang provide their own routing mechanisms, particularly ones that are not tied to the visual tree and that can support multiple command handlers. Creating a custom command implementation isn't hard. You implement the ICommand interface on a class, provide a way for command handlers to hook up, and then do the routing when the command is invoked. You also must decide what criteria you will use for determining when to raise the CanExecuteChanged event. A good starting point for creating a custom command is to use delegates. A delegate already supports invocation of a target method, and it also supports multiple subscribers. Figure 6 shows a custom command class called StringDelegateCommand that uses delegates to allow multiple handlers to hook up. It supports passing a string argument to the handlers, and it will use the CommandParameter of the invoker to determine what message is passed to the handlers. Figure 6 Custom Command Class public class StringDelegateCommand : ICommand Action<string> m_executetargets = delegate ; Func<bool> m_canexecutetargets = delegate return false; ; bool m_enabled = false; public bool CanExecute(object parameter) Delegate[] targets = m_canexecutetargets.getinvocationlist(); foreach (Func<bool> target in targets) m_enabled = false; bool localenable = target.invoke(); if (localenable) m_enabled = true; break; return m_enabled; public void Execute(object parameter) if (m_enabled) m_executetargets(parameter!= null? parameter.tostring() : null); public event EventHandler CanExecuteChanged = delegate ;... You can see I've chosen to use a Func<bool> delegate to hook up the handlers that will determine whether the command is enabled or not. In the implementation of CanExecute, the class loops through the handlers hooked up to the m_canexecutetargets delegate and sees whether any one handler wants to execute. If so, it returns true for the StringDelegateCommand to be enabled. When the Execute method is called, it simply checks to see if the command is enabled and, if so, invokes all the handlers hooked up to the m_executetargets Action<string> delegate. To hook up handlers to the CanExecute and Execute methods, the StringDelegateCommand class exposes the event accessors shown in Figure 7 to allow handlers to simply subscribe or unsubscribe from the underlying delegates. Notice that the event accessor also gives you the opportunity to trigger the CanExecuteChanged event whenever a handler subscribes or unsubscribes. Figure 7 Command Event Accessors public event Action<string> ExecuteTargets add m_executetargets += value; Understanding Routed Events and Commands In WPF Seite 10 von 12

120 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang remove m_executetargets -= value; public event Func<bool> CanExecuteTargets add m_canexecutetargets += value; CanExecuteChanged(this, EventArgs.Empty); remove m_canexecutetargets -= value; CanExecuteChanged(this, EventArgs.Empty); A Routed Handler Sample I've got this class hooked up in a sample application in the code download. The sample has a simple view with a presenter behind it (along the lines of MVP, but without the model). The presenter exposes a presentation model to the view for data binding (you can think of a presentation model as sitting between a presenter and a view, whereas the model of MVP sits behind the presenter from the view). The presentation model typically exposes properties to which the view can data bind. In this case, it just exposes a single property for the command so that it can be easily hooked up in the XAML of the view through data binding: <Window x:class="customcommandsdemo.simpleview"...> <Grid> <Button Command="Binding CookDinnerCommand" CommandParameter="Dinner is served!"...>cook Dinner</Button> <Button Click="OnAddHandler"...>Add Cook Dinner Handler</Button> </Grid> </Window> The Binding statement will just look for a property on the current DataContext, named CookDinnerCommand, and will try to cast that to an ICommand if it finds one. The CommandParameter was mentioned before, and it is a way for the invoker to pass some data along with the command. In this case, notice that I just pass the string that will be passed to the handlers through the StringDelegateCommand. The codebehind of the view (the Window class) is shown here: public partial class SimpleView : Window SimpleViewPresenter m_presenter = new SimpleViewPresenter(); public SimpleView() InitializeComponent(); DataContext = m_presenter.model; private void OnAddHandler(object sender, RoutedEventArgs e) m_presenter.addcommandhandler(); The view constructs its presenter, gets the presentation model from the presenter, and sets that as the DataContext. It also has the button Click handler, which calls into the presenter, asking it to add a handler for the command. Composite Events and Commands I've been working with the Microsoft patterns & practices group this year to help develop Composite Application Guidance for WPF, which is a set of guidance for developing complex composite applications in WPF. This set of guidance contains libraries, called the Composite Application Libraries (CAL), offering services and helper classes for composite applications. Read more about Composite Application Guidance for WPF in Glenn Block's article, "Patterns for Building Composite Applications with WPF," at msdn.microsoft.com/magazine/cc Figure 8 shows this application in action. The first window is in the initial state with no command handlers hooked up. You can see that the first button (the invoker) is disabled because there are no command handlers. Then when you press the second button, it calls into the presenter and hooks up a new command handler. The first button is then enabled, and when you click it, it invokes the command handler to which it is loosely coupled through a data binding and the underlying command's subscriber list. Understanding Routed Events and Commands In WPF Seite 11 von 12

121 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Figure 8 Custom Command Sample in Action (Click the image for a larger view) The presenter code is shown in Figure 9. You can see that the presenter constructs a presentation model and exposes it to the view through a Model property. When AddCommandHandler is called from the view (in response to the second button Click event), it adds a subscriber to the CanExecuteTargets and ExecuteTargets events on the model. These subscription methods are simple methods located in the presenter that return true and display a MessageBox, respectively. Figure 9 Presenter Class public class SimpleViewPresenter public SimpleViewPresenter() Model = new SimpleViewPresentationModel(); public SimpleViewPresentationModel Model get; set; public void AddCommandHandler() Model.CookDinnerCommand.CanExecuteTargets += CanExecuteHandler; Model.CookDinnerCommand.ExecuteTargets += ExecuteHandler; bool CanExecuteHandler() return true; void ExecuteHandler(string msg) MessageBox.Show(msg); This example shows that a combination of data binding, UI patterns, and custom commands can give you a clean, decoupled approach for commands without being tied to the limitations of routed commands. Because the command is hooked up in the XAML through a binding, you can even extend this approach to define your views with XAML only (no codebehind), use bound commands from the XAML to trigger actions in your presentation model, and initiate the action you would have normally done in codebehind from your presentation model instead. You'll need a controller for constructing the views and providing them with their presentation model, but you would be able to write interactive views without the need for codebehind. If you have no need for codebehind, there is much less opportunity for you to add tightly coupled and untestable spaghetti code in your codebehind file, as so often happens in UI apps. This approach is just beginning to be explored in WPF. But it is definitely something to consider, and you should be on the lookout for more examples. Brian Noyes is chief architect of IDesign ( a Microsoft Regional Director ( and a Microsoft MVP. He is the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding with Windows Forms 2.0. He is also a frequent speaker at industry conferences worldwide. Contact Brian through his blog at briannoyes.net. Understanding Routed Events and Commands In WPF Seite 12 von 12

122 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Contrasting the ADO.NET DataReader and DataSet John Papa Magazine Issues 2004 June I am often asked by developers whether the ADO.NET DataReader or the DataSet is the better tool. Some developers say the DataReader is better because it is lightweight, while still others say they prefer the DataSet for its inherent flexibility. The truth is that both have their place in Microsoft.NET development as their usefulness depends on the situation. The ADO 2.x recordset object is able to operate in either a connected or a disconnected mode. It can remain connected to the underlying database while traversing a forward-only rowset or it can retrieve a rowset into a client-side, in-memory cursor and disconnect itself from the database. Among the hurdles you may well encounter in migrating from classic ADO to ADO.NET is gaining a full understanding of how the operations that the ADO recordset performed are now handled in ADO.NET. Instead of a single rowset container, ADO.NET offers two distinctly separate data storage objects: the DataReader and the DataSet. This month I'll focus on the purpose of these two data retrieval classes in ADO.NET and help you to decide which is the best choice to use in a particular situation. I will explore how to retrieve data into both the DataReader and the DataSet, beginning by discussing the DataReader's unique capabilities. I will also compare the connected DataReader to the disconnected DataSet, weighing the pros and cons of using each in different scenarios. Being Connected Before deciding when to use a DataReader, it is smart to understand its features and limitations. The DataReader has a defined set of operations that revolve around its connected, forward-only, read-only nature (the read-only DataReader is also known as the firehose cursor of ADO.NET). A DataReader is a stream of data that is returned from a database query. When the query is executed, the first row is returned to the DataReader via the stream. The stream then remains connected to the database, poised to retrieve the next record. The DataReader reads one row at a time from the database and can only move forward, one record at a time. As the DataReader reads the rows from the database, the values of the columns in each row can be read and evaluated, but they cannot be edited. Unlike the DataSet, the DataReader is not implemented directly in the System.Data namespace. Rather, the DataReader is implemented through a specific managed provider's namespace such as System.Data.SqlClient.SqlDataReader. Because all DataReaders, including the OleDbDataReader, the SqlDataReader, and other managed provider's DataReaders implement the same IDataReader interface, they should all provide the same base set of functionality. Each DataReader is optimized for a specific data provider. If the database you are developing against has a managed provider for ADO.NET, then you should take advantage of it. Otherwise, you can use the System.Data.OleDb or the System.Data.Odbc namespaces, which expose more generic managed providers that can access a variety of data sources. If you are developing against SQL Server or Oracle, it would be more efficient to use the provider that was made specifically for these databases. In this column, I will query the SQL Server Northwind database using the System.Data.SqlClient namespace. The fact that the SqlDataReader is part of a specific managed provider's feature set further differentiates it from the DataSet. The SqlDataReader can only retrieve one row at a time from the data source and in order for it to get the next record, it has to maintain its connection to the data source. The DataSet, however, doesn't need to know about where it gets its data. Contrasting the ADO.NET DataReader and DataSet Seite 1 von 6

123 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang The DataReader can only get its data from a data source through a managed provider. The DataSet can also get its data from a data source via a managed provider, but the data source can also be loaded manually, even from an XML file on a hard drive. If the.net Framework does not provide a managed provider that is specifically designed for your database, it is certainly worth checking to see if the manufacturer or a third party has one available since they should perform better than the generic OLE DB and ODBC providers. In ASP.NET, DataReader objects can be used for more robust situations such as binding themselves to an ASP.NET DataGrid or a DropDownList server control. The following code demonstrates how to retrieve a list of products from the Northwind database using a SqlDataReader object: string ssql = "SELECT * FROM Products"; string sconnstring = "Server=(local);Database=Northwind;Integrated Security=SSPI;"; using (SqlConnection ocn = new SqlConnection(sConnString)) SqlCommand oselcmd = new SqlCommand(sSQL, ocn); oselcmd.commandtype = CommandType.Text; ocn.open(); SqlDataReader odr = oselcmd.executereader(); DataGrid1.DataSource = odr; DataGrid1.DataBind(); Both a SqlConnection and a SqlCommand object are created. The SqlConnection is opened and the SqlCommand object executes the SQL query, returning the first row to the SqlDataReader. At this point the connection to the database is still open and associated with the SqlDataReader. This code shows how a SqlDataReader can be bound to a bindable object such as an ASP.NET DataGrid. Alternatively, a DataReader could be used to retrieve the rows and then loop through them manually, one by one. It can support several resultsets as well. For example, a list of products and categories could be retrieved from a database. The following code retrieves a SqlDataReader and loops through its rows, writing the first column's value for each row to the console: SqlDataReader odr = ocmd.executereader(); while(odr.read()) Console.WriteLine(oDr[0]); Supporting Multiple Resultsets The DataReader supports access to multiple resultsets, one at a time, in the order they are retrieved. This code is easily modified to handle multiple resultsets. The following code retrieves a SqlDataReader and loops through its rows, again writing the first column's value for each row to the console: SqlDataReader odr = ocmd.executereader(); do while(odr.read()) Console.WriteLine(oDr[0]); Console.WriteLine(oDr[0]); while(odr.nextresult()); Once all of the rows from the first resultset are traversed, the rowset from the second query is retrieved and its rows are traversed and written. This process can continue for several resultsets using a single SqlDataReader. Contrasting the ADO.NET DataReader and DataSet Seite 2 von 6

124 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang The Read method of the SqlDataReader loads the next record so that it can be accessed and moves the position of the cursor ahead. It returns a Boolean value indicating the existence of more records. This feature can help circumvent a common problem in classic ADO development: the endless loop. In classic ADO, when looping through a recordset object developers would often omit the MoveNext method and run the code only to remember a second too late that this would cause the recordset to loop infinitely on the same record. ADO.NET is kind to developers as its DataReader object's Read method automatically moves the position to the next record so this situation can't occur. The NextResult method of the SqlDataReader object retrieves the subsequent rowset and makes it accessible to the SqlDataReader. It also returns a Boolean value indicating if there are additional resultsets to traverse, like the Read method does. The DataReader in the previous code sample shows how to get the value for a column from the DataReader using its ordinal index position. Can the DataReader be indexed by the column name or can the index of the column be retrieved? The answer to both of these questions is yes. The code in Figure 1 shows how a DataReader retrieves data and displays the CompanyName for each row in the diagnostics' output window. Figure 1 Retrieving and Displaying Data string sconnstring = "Server=(local);Database=Northwind;Integrated Security=SSPI;"; using(sqlconnection ocn = new SqlConnection(sConnString)) SqlCommand ocmd = new SqlCommand("SELECT * FROM Customers", ocn); ocn.open(); SqlDataReader odr = ocmd.executereader(commandbehavior.closeconnection); while(odr.read()) System.Diagnostics.Debug.WriteLine("Company Name " + odr["companyname"]); System.Diagnostics.Debug.WriteLine("Company Name: name = " + odr.getname(1)); System.Diagnostics.Debug.WriteLine("Company Name: index = " + odr.getordinal("companyname")); To demonstrate these techniques, this code displays the CompanyName value, column name, and index. The first line in the loop writes the CompanyName using the value representing the name of the CompanyName column. This could also have been accomplished by passing the index of 1. I avoid this as it is less clear which column you are accessing, although using the string value is slower than using the index. The second line in the loop writes the name of the column at position 1 (CompanyName) using the GetName method. The third line gets the index of the CompanyName column using the GetOrdinal method of the SqlDataReader. You might also notice that the CommandBehavior is set to CloseConnection, ensuring that the connection will be closed when the SqlDataReader is closed. These methods are simple but they make the SqlDataReader a power tool. The Disconnected Side The DataSet is the main data storage tool in the ADO.NET disconnected architecture. Unlike the DataReader, the DataSet is not connected directly to a database through a Connection object when you populate it. Instead, to fill a DataSet from a database you first create a DataAdapter object (such as a SqlDataAdapter) for the provider and associate it with a SqlConnection object. Then the SqlDataAdapter can broker the data retrieval for the DataSet Contrasting the ADO.NET DataReader and DataSet Seite 3 von 6

125 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang by issuing a SqlCommand against the database through the SqlConnection, retrieving the data, and filling the DataSet. You can think of the SqlDataAdapter as a bridge between the connected and disconnected objects. One of its purposes is to serve as the route for a rowset to get from the database to the DataSet. For example, when the SqlDataAdapter's Fill method is executed it opens its associated SqlConnection object (if not already open) and issues its associated SqlCommand object against the SqlConnection. Behind the scenes, a SqlDataReader is created implicitly and the rowset is retrieved one row at a time in succession and sent to the DataSet. Once all of the data is in the DataSet, the implicit SqlDataReader is destroyed and the SqlConnection is closed. The following code shows how a DataSet can be filled from the Products table of the Northwind database. Notice that there is no explicit SqlDataReader object in this code sample: string ssql = "SELECT * FROM Products"; string sconnstring = "Server=(local);Database=Northwind;Integrated Security=SSPI;"; SqlDataAdapter oda = new SqlDataAdapter(); DataSet ods = new DataSet(); using(sqlconnection ocn = new SqlConnection(sConnString)) SqlCommand oselcmd = new SqlCommand(sSQL, ocn); oselcmd.commandtype = CommandType.Text; oda.selectcommand = oselcmd; oda.fill(ods, "Products"); The DataSet can read and load itself from an XML document as well as export its rowset to an XML document. Because the DataSet can be represented in XML, it can be easily transported across processes, a network, or even the Internet via HTTP. Unlike the DataReader, the DataSet is not read-only. A DataSet can be modified, and rows can be added or deleted. Changes to a DataSet can be sent to the database via a managed provider's objects. Another key difference between the DataSet and the DataReader is that the DataSet is fully navigable. Its rows can be traversed forward or backward. The DataReader can be traversed forward only. In addition, a DataSet is highly flexible in that its DataTable objects can be filtered vertically or horizontally and they can be sorted or even searched. The DataSet is independent of any one data provider as it relies on a DataAdapter specific to each provider to broker the data between the DataSet and the database. Not only can the DataSet be loaded from XML, it can also be loaded manually. Notice in Figure 2 how a DataTable is created and its columns added manually. A primary key constraint is established as well as an auto-incrementing value for the key field. Then the DataTable is added to an empty DataSet (though is doesn't have to be empty) and the rows are added one by one to the DataTable, all without ever connecting to a data source. Figure 2 Creating a DataSet Manually //-- Create the table DataTable odt = new DataTable("Employees"); DataRow orow; odt.columns.add("employeeid", System.Type.GetType("System.Int32")); odt.columns.add("firstname", System.Type.GetType("System.String")); odt.columns.add("lastname", System.Type.GetType("System.String")); odt.constraints.add("pk_employees", odt.columns["employeeid"], true); odt.columns["employeeid"].autoincrement = true; odt.columns["employeeid"].autoincrementseed = -1000; odt.columns["employeeid"].autoincrementstep = -1; ods.tables.add(odt); //-- Add the rows orow = ods.tables["employees"].newrow(); Contrasting the ADO.NET DataReader and DataSet Seite 4 von 6

126 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang orow["firstname"] = "Haley"; orow["lastname"] = "Smith"; ods.tables["employees"].rows.add(orow); orow = ods.tables["employees"].newrow(); orow["firstname"] = "Madelyn"; orow["lastname"] = "Jones"; ods.tables["employees"].rows.add(orow); //-- Bind it to a DataGrid grdemployees.datasource = ods.tables["employees"]; Because the DataSet is disconnected, its use can reduce the demand on database servers. It does, however, increase the memory footprint in the tier where it is stored, so be sure to account for that when designing around a DataSet as your data store. Scaling up on the middle tier using parallel servers and load balancing is a common way to handle the increased load so that session-based information can be stored in objects such as the DataSet. When to Use the DataSet Your situation will dictate when and where you'll use a DataSet versus a DataReader. For example, the DataSet's disconnected nature allows it to be transformed into XML and sent over the wire via HTTP if appropriate. This makes it ideal as the return vehicle from businesstier objects and Web services. A DataReader cannot be serialized and thus cannot be passed between physical-tier boundaries where only string (XML) data can go. DataSet objects are a good choice when the data must be edited or rows added or deleted from the database. It is not the only choice, however, as a DataReader could be used to retrieve the data and changes would be sent to the database via a SqlDataAdapter through a separate, selfmaintained DataRow array. That process can be quite messy because the SqlDataReader cannot allow edits as the DataSet can. As mentioned earlier, the DataSet is also a good choice when you need data manipulation such as filtering, sorting, or searching. Since the DataSet can be traversed in any direction, all of these features are available. This flexibility also makes the DataSet an easy choice when the situation calls for multiple iterations of the rowset. A DataReader can move forward only, so to loop through it more than once, the DataReader would be closed and reopened and the query would hit the database a second time. If a rowset is intended to be bound to a single ASP.NET server control and the data is readonly, the DataReader could suffice. If a rowset is intended to be bound to more than one readonly ASP.NET server control, you should consider using a DataSet instead. If a DataReader was bound to more than one control (such as three DropDownList controls), the same query would hit the database three times since the DataReader can only move forward. The DataSet also works well when a rowset must be persisted between page calls to the Session or Cache objects. Of course, because the DataReader is associated with a specific data source, it cannot be created, filled, or traversed without a connection to the data source. Unlike the DataReader, a DataSet can be created manually without a connection to the source. In a situation such as an online shopping cart in which a custom data store is required, a DataSet could be created manually and its rows added. Another good use of the DataSet is the situation in which data must be retrieved and a complex action performed on each row. For example, an application might retrieve a hundred stock and mutual fund symbols from a 401k table that needs to be edited. This data might have to include the stock and mutual fund prices on screen, as well. A DataSet could be used to store the rowset and some code could loop through the DataSet and perform a lookup of each stock's price through a third-party Web service. Finally, one of the more compelling reasons to use a DataSet instead of a DataReader is that the DataSet can be serialized when Contrasting the ADO.NET DataReader and DataSet Seite 5 von 6

127 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang the rowset needs to be passed around a network or the Internet. A DataReader cannot be serialized to XML due to its connected nature. The DataSet is not the best solution in every situation, and there are several situations in which DataReaders should really be considered. One is when an application implements a.net architecture without data binding situations in which manual updates to the database are performed and controls are loaded by looping through rowsets. DataReaders are a good choice when an application has to be sensitive to changes in the underlying database. There are other times when a DataReader can be the right choice, such as when populating a list or retrieving 10,000 records for a business rule. When a huge amount of data must be retrieved to a business process, even on a middle tier, it can take a while to load a DataSet, pass the data to it on the business tier from the database, and then store it in memory. The footprint could be quite large and with numerous instances of it running (such as in a Web application where hundreds of users may be connected), scalability would become a problem. If this data is intended to be retrieved and then traversed for business rule processing, the DataReader could speed up the process as it retrieves one row at a time and does not require the memory resources that the DataSet requires. When output or return parameters need to be retrieved, a DataReader will not allow you to get them until the DataReader and its connection are closed. If data must be bound to a read-only list in a Web Form, a DataReader is a very good choice. Binding a DataReader to a DropDownList or even a read-only DataGrid in ASP.NET works well as the data can be retrieved and displayed in the list but does not need to be persisted for editing. DataSets are ideal if data needs to be edited, sorted, filtered, or searched. As I have shown, when data must be passed without a connection to a database or when rich features for manipulating the data are required, a DataSet fits the bill nicely. The DataReader works well when a simpler purpose for the data exists such as populating a dropdown list or retrieving tens of thousands of rows for processing. Your decision should be based on the particular factors of the situation of the application. Contrasting the ADO.NET DataReader and DataSet Seite 6 von 6

128 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Configuration Overview: ASP.NET By Brij Introduction Here in this article, I will be exploring the configuration files of a website. ASP.NET website configuration is normally a combination of two files: machine.config web.config Here, I'll concentrate on web.config and give an overview of machine.config. Every time we install the.net framework, there is a machine.config file that is created in "C:\WINDOWS\Microsoft.NET\Framework\[Version]\CONFIG", which mainly defines: Supported configuration file sections, the ASP.NET worker process configuration, and registers different providers that are used for advanced features such as profiles, membership, and role based security. To explore the web.config might take a book, but here, I'll try to explore all the important sections that play a pivotal role for an ASP.NET website and its deployment. Every web application inherits settings from the machine.config file, and application level setting is done in the web.config file. We can also override configurations in the machine.config file in the web.config file. But, a few settings can not be overridden because certain settings are process model settings and can't be changed on a per application basis. The entire contents of a configuration file, whether it is machine.config or web.config, is nested in a <configuration> element. ASP.NET Multilayered Configuration system ASP.NET uses a multilayered configuration system that allows for using different settings for different parts of an application. For this, we must have an additional subdirectory inside the virtual directory, and these subdirectories will contain their own config files with additional settings. ASP.NET uses configuration inheritance so that each subdirectory acquires the settings from the parent directory. Configuration Overview: ASP.NET Seite 1 von 9

129 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Let's take an example. We have a web request where X is the root directory of the application. In this case, multiple levels of settings come into the picture. 1. The default machine.config settings are applied first. 2. Next, the web.config of the root level is applied. This web.config resides in the same config directory as the machine.config file. 3. Now, if there is any config file in the application root X, these settings are applied. 4. If there is any config file in the subdirectory Y, these settings are now applied. 5. If there is any config file in the application root Z, those settings are then applied. But here, there is a limitation: we can have unlimited number of subdirectories having different settings, but the configuration at step 1 and 2 are more significant because some of the settings can not be overridden, like the Windows account that is to be used to execute the code, and other settings can be only overridden at the application root level, like the type of authentication to be used etc. Different config files are useful when we apply different security settings to different folders. The files that need to be secured would then be placed in a separate folder with a separate web.config file that defines the more stringent security settings to these files and vice versa. In the web.config, under the <configuration> element, there is another element <system.web>, which is used for ASP.NET settings and contains separate elements for each aspect of the configuration. Configuration Overview: ASP.NET Seite 2 von 9

130 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Important Configuration Tags There are a lot of configuration tags that are provided by the web.config file, like authentication, authorization, browsercaps, clienttarget etc., but all of these don't have that much importance (and also can't be covered in a single article ), so here, I have only concentrated on the main tags of the config file. <authentication> This element is used to verify the client's identity when the client requests a page from the server. This is set at the application level. We have four types of authentication modes: None, Windows, Forms, and Passport. If we don't need any authentication, this is the setting we use: <authentication mode="none"/> Normally, Windows authentication is used, for which, we need to check the checkbox: Integrated Windows Authentication. <authentication mode="windows"/> This authentication is handled by IIS. When the user sends a request to the server, IIS authenticates it and sends the authentication identity to the code. IIS gives us four choices for the authentication modes: Anonymous, Basic, Digest, and Windows Integrated. If the user selects Anonymous, then IIS doesn't perform any authentication. For Basic authentication, the user has to provide a username and password. This authentication is very unsecure, because the user credentials are sent in clear text format over the network. Digest authentication is same as Basic, except it hashes the user's password and transmits the hashed version over the wire. So, it is more secure than Basic. For Windows Integrated Configuration Overview: ASP.NET Seite 3 von 9

131 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang authentication, passwords never cross the network. The user must still have a username and password, but the application uses either the Kerberos or a challenge/response protocol to authenticate the user. Forms authentication uses web application forms to collect user credentials, and on the basis of the credential, it takes action on a web application. <authentication mode="forms"> <forms name="form" loginurl="index.asp" /> </authentication> Passport authentication is provided by Microsoft. A redirect URL should be specified, and is used when the requested page is not authenticated, and then it redirects to this URL. <authentication mode="passport"> <passport redirecturl="internal" /> </authentication> Here, users are authenticated using the information in Microsoft's Passport database. The advantage is, we can use existing user credentials (such as an address and password) without forcing users to go through a separate registration process. The disadvantage is we need to go through the licensing agreement with Microsoft and pay a yearly fee based on the use. For using Passport authentication, you first install the Passport Software Development Kit (SDK) on your server. The SDK can be downloaded from here. It includes full details of implementing passport authentication in your own applications. <authorization> The <authorization> tag controls client access to web page resources. This element can be declared at any level (machine, site, application, subdirectory, or page). authorization> <allow users="comma-separated list of users" roles="comma-separated list of roles" verbs="comma-separated list of verbs"/> <deny users="comma-separated list of users" roles="comma-separated list of roles" verbs="comma-separated list of verbs"/> </authorization> <allow>: Using this tag, we can control access to resources on the basis of the following verbs. In these attributes, we use symbols:? and *.? means for anonymous users/resources, and * means for all users. users: This contains the list of user names (comma separated) that are allowed to access the resources. roles: This contains the list of roles (comma separated) that are allowed to access the resources. verbs: This contains the list of HTTP verbs to which the action applies (comma separated). It is used to create a rule that applies to a specific type of HTTP request (GET, POST, HEAD, OR DEBUG). Configuration Overview: ASP.NET Seite 4 von 9

132 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang <deny>: Using this tag, we can control access to resources on the basis of the following verbs: users: This contains the list of users names (comma separated) that are denied access to the resources. roles: This contains the list of roles (comma separated) that are denied access to the resources. verbs: This contains the list of HTTP verbs to which the action applies (comma separated). It is used to create a rule that applies to a specific type of HTTP request (GET, POST, HEAD, OR DEBUG). <compilation> In this section, we can configure the settings of the compiler. Here, we can have lots of attributes, but the most common ones are debug and defaultlanguage. Setting debug to true means we want the debugging information in the browser, but it has a performance tradeoff, so normally, it is set as false. And, defaultlanguage tells ASP.NET which language compiler to use: VB or C#. <customerrors> This tags includes the error settings for the application, and is used to give custom error pages (user-friendly error pages) to end users. In the case that an error occurs, the website is redirected to the default URL. For enabling and disabling custom errors, we need to specify the mode attribute. <customerrors defaultredirect="url" mode="off"> <error statuscode="403" redirect="/accesdenied.html" /> <error statuscode="404" redirect="/pagenotfound.html" /> </customerrors> "On" means this settings is on, and if there is any error, the website is redirected to the default URL. "Off" means the custom errors are disabled. "RemoteOnly" shows that custom errors will be shown to remote clients only. <error statuscode="403" redirect="/accesdenied.html" /> <error statuscode="404" redirect="/pagenotfound.html" /> This means if there is an error of 403, then the website will redirected to the custom page accessdenied.html. Similarly for 404 as defined above. Note: If an error occurs in the custom error page itself, ASP.NET won't able to handle it. It won't try to reforward the user to the same page. Instead, it'll show the normal default client error page with a generic message. <globalization> This section is used when we want to use encoding or specify a culture for the application. This is a very vast topic, and can take an article itself for explaining it. Here, we define the character set for the server to send the response to the client, which is by default is UTF-8, Configuration Overview: ASP.NET Seite 5 von 9

133 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang and the settings of which the server should use to interpret and display culturally specific strings, such as numbers and dates. globalization requestencoding="utf-8" responseencoding="utf-8" /> <httpruntime> This section can be used to configure the general runtime settings of the application. The main two are: <httpruntime apprequestqueuelimit="50" executiontimeout="300" /> As the name suggests, the attribute apprequestqueuelimit defines the number of requests that can be queued up on the server for processing. If there are 51 or more requests, then server would return the 503 error ("Server too busy"). The attribute executiontimeout defines the number of minutes ASP.NET will process a request before it gets timeout. <trace> As the name suggestz, it is used for tracing the execution of an application. We have here two levels of tracing: page level and application level. Application level enables the trace log of the execution of every page available in the application. If pageoutput="true", trace information will be displayed at the bottom of each page. Else, we can view the trace log in the application root folder, under the name trace.axd. <trace enabled="false" requestlimit="10" pageoutput="false" tracemode="sortbytime" locaonly="true" /> Set the attribute localonly to false for not viewing the trace information from the client. For enabling trace at page level, set Trace="True" in the Page tag (on the top of the page). <identity> Using this tag, we can control the identity of the application. By default, Impersonation is disabled. Using Impersonation, an ASP.NET application can execute optionally with the identity of a client on whose behalf they are operating. <identity impersonate="false" username="domain\username" password="password" /> <sessionstate> In this section, we tell ASP.NET where to store the session. By default, it's inproc which means storing the session values on the server. But we have four options: "Off" means session is not enabled for the application. "inproc" means storing the session values on the server. Configuration Overview: ASP.NET Seite 6 von 9

134 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang "StateServer" means session states are stored in a remote server. "SQLServer" means session states are stored in a SQL Server database. For this, we need to install the InstallSQLState.sql script in the SQL Server database. It is mainly used when the we use web farms (an application deployed on multiple servers), but it makes the performance slow as compared to "inproc". Here are the other settings: "cookieless": when it is true, it means the session used is without cookies. timeout specifies after how much time the session would expire if the application is not accessed during that period. "stateconnectionstring" needs to be specified when the session mode is StateServer. "sqlconnectionstring" is the connection string of the SQL Server database if the session mode is sqlserver. "statenetworktimeout" attribute, when using the StateServer mode to store session state, specifies the number of seconds the TCP/IP network connection between the web server and the state server can be idle before the session is abandoned. The default is 10. <sessionstate mode="off" cookieless="true" timeout="100" stateconnectionstring="tcpip=server:port" sqlconnectionstring="sql connection string" statenetworktimeout="number of seconds"/> <appsettings> This section is used to store custom application configuration like database connection strings, file paths etc. This also can be used for custom application-wide constants to store information over multiple pages. It is based on the requirements of the application. <appsettings> <add key=" to" value="me@microsoft.com" /> <add key="cssfile" value="css/text.css" /> </appsettings> It can be accessed from code like: ConfigurationSettings.AppSettings(" to"); All the values returned from it are strings. Custom Configuration Sections We might need some custom configuration sections based on the requirements. One of the simplest ways we can do this is to create our own named sections, and we can use existing NameValueSectionHandler components to parse them, and they can be used as key/value pairs to be accessed at run-time. Configuration Overview: ASP.NET Seite 7 von 9

135 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang This can be read very easily accessed from the code-behind as: private string ReadCustomSection() string strkey = "mysectionkey1"; NameValueCollection nvcmysection = (NameValueCollection) ConfigurationSettings.GetConfig("mySection"); string strvalueofkey = nvcmysection[strkey]; return strvalueofkey; There are more ways for using custom configuration sections. Check this article: CustomConfigurationSection. Encrypting Configuration Sections Some times, we put some sensitive data in the web.config file like connection strings, user specific details etc. It is recommended to encrypt these sections. ASP.NET supports two encryption techniques. RSA DPAPI The way the operations perform is very simple. When retrieving information from a config file, ASP.NET automatically decrypts it and gives the plain text to the code. Similarly, if we do any updates on the config file from code, it is done the same way. We cannot update a config file directly. But, we can use WAT for updating it. Programmatic encryption techniques: If we want to do encryption programmatically, then we need to retrieve the corresponding ConfigurationSection.SectionInformation object and call the ProtectSection() method. If we want to decrypt a section, then we can call the method UnprotectSetion(). Sample code is shown here: Configuration myconfig = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath); Configuration Overview: ASP.NET Seite 8 von 9

136 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang ConfigurationSection mysettings = myconfig.getsection("mysection"); if (mysettings.sectioninformation.isprotected) mysettings.sectioninformation.unprotectsection(); else mysettings.sectioninformation.protectsection("dataprotectionconfigurationpr ovider"); ; myconfig.save(); Command line utilities: We can also use a command line utility like aspnet_regiis.exe for encryption of a config file, which is a CAB file found in C:\[WinDir]\Microsoft.NET\Framework\[Version]. For using this tool, we must create a virtual directory for the application. You can refer my article, Deploying Website at IIS, for more information. When using aspnet_regiis to protect some sections of a config file, we need to specify some command line arguments such as: The -pe switch specifies the configuration section to encrypt. The -app switch specifies our web application virtual path. The -prov switch specifies the provider name. Here is the command line for an application located at A Few Important Points Some settings can not be encrypted because they are used outside ASP.NET (mainly by the IIS web server), like <httpruntime>. Config files are case sensitive. The web.config file is protected by IIS, so it won't be accessible by a client system. So, if a user tries to access it, anaccess denied message will be shown. If we change the config file at the server, we don't need to restart the web server because IIS monitors the changes in the web.config, and for performance measures, it cache it. Microsoft also provides a tool known as Website Administration Tool (WAT) that lets us configure various part of the web.config using a web interface. To run it, select Website->ASP.NET Configuration, in Visual Studio. Configuration Overview: ASP.NET Seite 9 von 9

137 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang Erstellen von Webanwendungen ohne Webformulare Chris Tavares MSDN Magazin, März Dieser Artikel basiert auf der Vorabversion von ASP.NET MVC Framework. Änderungen der Details in diesem Artikel sind vorbehalten. Dieses neue Framework basiert auf dem Model View Controller (MVC)-Muster, daher der Name ASP.NET MVC. Das MVC-Muster wurde ursprünglich in den 70er Jahren als Teil von Smalltalk erfunden. Wie in diesem Artikel aufgezeigt wird, passt es hervorragend zur Funktionsweise des Internets. MVC teilt die Benutzeroberfläche in drei unterschiedliche Objekte ein: den Controller, der Eingaben empfängt und behandelt, das Modell, das die Domänenlogik enthält, und die Ansicht, die die Ausgabe generiert. Im Kontext des Internets ist die Eingabe eine HTTP-Anforderung, und der Anforderungsfluss sieht wie Abbildung 1 aus. Abbildung 1 MVC- Musteranforderungsfluss (Klicken Sie zum Vergrößern auf das Bild) Dies unterscheidet sich erheblich vom Prozess in Webformularen. Im Webformularmodell geht die Eingabe zur Seite (Ansicht), und die Ansicht ist sowohl für die Verarbeitung der Eingabe als auch das Generieren der Ausgabe verantwortlich. Bei MVC sind die Verantwortlichkeiten getrennt. Wahrscheinlich gehen Ihnen jetzt zwei Dinge durch den Kopf. Entweder: Das ist großartig. Wie genau geht das? oder: Warum sollte ich drei Objekte schreiben, wenn ich zuvor nur eins schreiben musste? Beides sind gute Fragen und können am besten anhand eines Beispiels erklärt werden. Um die Vorzüge diese Methode zu veranschaulichen, zeige ich Ihnen hier das Schreiben einer kleinen Webanwendung mithilfe von MVC Framework auf. Erstellen eines Controllers Um folgen zu können, müssen Sie Visual Studio 2008 installieren und eine Kopie von MVC Framework abrufen. Zum Zeitpunkt dieses Artikels ist es als Teil des Community Technology Preview (CTP) der ASP.NET-Erweiterungen vom Dezember 2007 verfügbar (asp.net/downloads/3.5-extensions). Laden Sie die CTP-Erweiterungen und das MVC-Toolkit herunter, das einige nützliche Hilfsobjekte enthält. Nachdem Sie CTP heruntergeladen und installiert haben, wird im Dialogfeld für neue Projekte ein neues ASP.NET MVC Webanwendungsprojekt angezeigt. Durch Auswählen dieses MVC-Webanwendungsprojekts erhalten Sie eine Lösung, die etwas anders aussieht als eine normale Website oder Anwendung. Die Lösungsvorlage erstellt eine Webanwendung mit einigen neuen Verzeichnissen (siehe Abbildung 2). Vor allem enthält Erstellen von Webanwendungen ohne Webformulare Seite 1 von 14

138 Dr. Ute Blechschmidt-Trapp,.Net Framework und C# SS 2010 Anhang das Controllerverzeichnis die Controllerklassen, und das Ansichtenverzeichnis (und alle seine Unterverzeichnisse) enthält die Ansichten. Abbildung 2 Die MVC-Projektstruktur Sie schreiben jetzt einen sehr einfachen Controller, der einen Namen zurückgibt, der auf der URL übergeben wird. Klicken Sie mit der rechten Maustaste auf den Ordner Controller. Durch Auswahl von Element hinzufügen wird das bekannte Dialogfeld Neues Element hinzufügen mit einigen neuen Elementen angezeigt, einschließlich einer MVC-Controllerklasse und verschiedenen MVC-Ansichtskomponenten. In diesem Fall fügen Sie eine Klasse namens HelloController hinzu: using System; using System.Web; using System.Web.Mvc; namespace HelloFromMVC.Controllers public class HelloController : Controller [ControllerAction] public void Index()... Eine Controllerklasse ist viel leichter als eine Seite. Eigentlich sind nur das Ableiten von System.Web.Mvc.Controller und das Weitergeben des Attributs [ControllerAction] an die Aktionsmethoden wirklich erforderlich. Eine Aktion ist eine Methode, die als Reaktion auf eine Anforderung an eine bestimmte URL aufgerufen wird. Aktionen sind für die erforderliche Verarbeitung und das anschließende Rendern einer Ansicht verantwortlich. Zunächst schreiben Sie eine einfache Aktion, die den Namen an die Ansicht übergibt, wie Sie hier sehen: [ControllerAction] public void HiThere(string id) ViewData["Name"] = id; RenderView("HiThere"); Die Aktionsmethode erhält den Namen von der URL über den id-parameter (später genaueres über das Wie), speichert ihn in der ViewData-Sammlung und rendert dann eine Ansicht namens HiThere. Bevor das Aufrufen dieser Methode oder das Aussehen der Ansicht erläutert werden, soll näher auf Testfähigkeit eingegangen werden. Erinnern Sie sich an die vorherigen Anmerkungen darüber, wie schwer Webformularseitenklassen zu testen sind? Nun, Controller lassen sich viel leichter testen. In der Tat ist es ohne zusätzliche Infrastruktur möglich, einen Controller direkt zu instanziieren und Aktionsmethoden aufzurufen. Es sind kein HTTP- Kontext und kein Server erforderlich, lediglich eine Testumgebung. Als Beispiel habe ich für diese Klasse in Abbildung 3 einen Visual Studio Team System (VSTS)-Komponententest eingefügt. Figure 3 Controllerkomponententest namespace HelloFromMVC.Tests [TestClass] Erstellen von Webanwendungen ohne Webformulare Seite 2 von 14

Delegatesund Ereignisse

Delegatesund Ereignisse Delegatesund Ereignisse «Delegierter» Methoden Schablone Funktionszeiger Dr. Beatrice Amrhein Überblick Definition eines Delegat Einfache Delegate Beispiele von Delegat-Anwendungen Definition eines Ereignisses

Mehr

3. Auflage. O Reillys Taschenbibliothek. C# 5.0 kurz & gut. Joseph Albahari & Ben Albahari O REILLY. Aktualisierung von Lars Schulten

3. Auflage. O Reillys Taschenbibliothek. C# 5.0 kurz & gut. Joseph Albahari & Ben Albahari O REILLY. Aktualisierung von Lars Schulten O Reillys Taschenbibliothek 3. Auflage C# 5.0 kurz & gut O REILLY Joseph Albahari & Ben Albahari Aktualisierung von Lars Schulten Inhalt C# 5.0 kurz & gut... 1 Ein erstes C#-Programm... 2 Syntax... 5 Typgrundlagen...

Mehr

C# im Vergleich zu Java

C# im Vergleich zu Java C# im Vergleich zu Java Serhad Ilgün Seminar Universität Dortmund SS 03 Gliederung Entstehung von C# und Java Überblick von C# und Java Unterschiede und Gemeinsamkeiten Zusammenfassung und Ausblick Entstehung

Mehr

Vererbung & Schnittstellen in C#

Vererbung & Schnittstellen in C# Vererbung & Schnittstellen in C# Inhaltsübersicht - Vorüberlegung - Vererbung - Schnittstellenklassen - Zusammenfassung 1 Vorüberlegung Wozu benötigt man Vererbung überhaubt? 1.Um Zeit zu sparen! Verwendung

Mehr

Objektorientierte Programmierung. Kapitel 12: Interfaces

Objektorientierte Programmierung. Kapitel 12: Interfaces 12. Interfaces 1/14 Objektorientierte Programmierung Kapitel 12: Interfaces Stefan Brass Martin-Luther-Universität Halle-Wittenberg Wintersemester 2012/13 http://www.informatik.uni-halle.de/ brass/oop12/

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags keine Pommes... Praktikum A 230 C 207 (Madeleine + Esma) F 112 F 113

Mehr

Vorkurs C++ Programmierung

Vorkurs C++ Programmierung Vorkurs C++ Programmierung Klassen Letzte Stunde Speicherverwaltung automatische Speicherverwaltung auf dem Stack dynamische Speicherverwaltung auf dem Heap new/new[] und delete/delete[] Speicherklassen:

Mehr

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben.

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben. Aufgabe 1.30 : Schreibe ein Programm DM_in_Euro.java zur Umrechnung eines DM-Betrags in Euro unter Verwendung einer Konstanten für den Umrechnungsfaktor. Das Programm soll den DM-Betrag als Parameter verarbeiten.

Mehr

8 Design Patterns. Events

8 Design Patterns. Events 8 Design Patterns. Events Jörn Loviscach Versionsstand: 28. März 2015, 19:13 Die nummerierten Felder sind absichtlich leer, zum Ausfüllen beim Ansehen der Videos: http://www.j3l7h.de/videos.html This work

Mehr

Übung 1 mit C# 6.0 MATTHIAS RONCORONI

Übung 1 mit C# 6.0 MATTHIAS RONCORONI Übung 1 mit C# 6.0 MATTHIAS RONCORONI Inhalt 2 1. Überblick über C# 2. Lösung der Übung 1 3. Code 4. Demo C# allgemein 3 aktuell: C# 6.0 mit.net-framework 4.6: Multiparadigmatisch (Strukturiert, Objektorientiert,

Mehr

Programmieren in Java

Programmieren in Java Programmieren in Java objektorientierte Programmierung 2 2 Zusammenhang Klasse-Datei In jeder *.java Datei kann es genau eine public-klasse geben wobei Klassen- und Dateiname übereinstimmen. Es können

Mehr

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu Daten Makro + VBA effektiv 5 DATEN 5.1. Variablen Variablen können beliebige Werte zugewiesen und im Gegensatz zu Konstanten jederzeit im Programm verändert werden. Als Variablen können beliebige Zeichenketten

Mehr

Grundlagen von Python

Grundlagen von Python Einführung in Python Grundlagen von Python Felix Döring, Felix Wittwer November 17, 2015 Scriptcharakter Programmierparadigmen Imperatives Programmieren Das Scoping Problem Objektorientiertes Programmieren

Mehr

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java: Technische Informatik für Ingenieure (TIfI) WS 2005/2006, Vorlesung 9 II. Grundlagen der Programmierung Ekkart Kindler Funktionen und Prozeduren Datenstrukturen 9. Datenstrukturen Daten zusammenfassen

Mehr

Java: Vererbung. Teil 3: super() www.informatikzentrale.de

Java: Vererbung. Teil 3: super() www.informatikzentrale.de Java: Vererbung Teil 3: super() Konstruktor und Vererbung Kindklasse ruft SELBSTSTÄNDIG und IMMER zuerst den Konstruktor der Elternklasse auf! Konstruktor und Vererbung Kindklasse ruft SELBSTSTÄNDIG und

Mehr

SEP 114. Design by Contract

SEP 114. Design by Contract Design by Contract SEP 114 Design by Contract Teile das zu entwickelnde Programm in kleine Einheiten (Klassen, Methoden), die unabhängig voneinander entwickelt und überprüft werden können. Einheiten mit

Mehr

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag Ludwig-Maximilians-Universität München WS 2015/16 Institut für Informatik Übungsblatt 9 Prof. Dr. R. Hennicker, A. Klarl Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung:

Mehr

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Objektorientierte Programmierung für Anfänger am Beispiel PHP Objektorientierte Programmierung für Anfänger am Beispiel PHP Johannes Mittendorfer http://jmittendorfer.hostingsociety.com 19. August 2012 Abstract Dieses Dokument soll die Vorteile der objektorientierten

Mehr

Tutorium Rechnerorganisation

Tutorium Rechnerorganisation Woche 2 Tutorien 3 und 4 zur Vorlesung Rechnerorganisation 1 Christian A. Mandery: KIT Universität des Landes Baden-Württemberg und nationales Grossforschungszentrum in der Helmholtz-Gemeinschaft www.kit.edu

Mehr

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren: 5. Abstrakte Klassen Beispiel 5. Abstrakte Klassen 5. Abstrakte Klassen Beispiel Beispiel (3) Angenommen, wir wollen die folgende Klassenhierarchie implementieren: Probleme des Implementierungsvorschlags:

Mehr

Programmierkurs Java

Programmierkurs Java Programmierkurs Java Dr. Dietrich Boles Aufgaben zu UE16-Rekursion (Stand 09.12.2011) Aufgabe 1: Implementieren Sie in Java ein Programm, das solange einzelne Zeichen vom Terminal einliest, bis ein #-Zeichen

Mehr

Java Einführung Collections

Java Einführung Collections Java Einführung Collections Inhalt dieser Einheit Behälterklassen, die in der Java API bereitgestellt werden Wiederholung Array Collections (Vector, List, Set) Map 2 Wiederholung Array a[0] a[1] a[2] a[3]...

Mehr

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen Binäre Bäume 1. Allgemeines Binäre Bäume werden grundsätzlich verwendet, um Zahlen der Größe nach, oder Wörter dem Alphabet nach zu sortieren. Dem einfacheren Verständnis zu Liebe werde ich mich hier besonders

Mehr

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {... PIWIN I Kap. 8 Objektorientierte Programmierung - Vererbung 31 Schlüsselwort: final Verhindert, dass eine Methode überschrieben wird public final int holekontostand() {... Erben von einer Klasse verbieten:

Mehr

Starthilfe für C# Inhaltsverzeichnis. Medien- und Kommunikationsinformatik (B.Sc.) Alexander Paharukov. Informatik 3 Praktikum

Starthilfe für C# Inhaltsverzeichnis. Medien- und Kommunikationsinformatik (B.Sc.) Alexander Paharukov. Informatik 3 Praktikum Starthilfe für C# Inhaltsverzeichnis Allgemeines... 2 Bezugsquellen... 2 SharpDevelop... 2.NET Runtime... 2.NET SDK... 2 Installation... 2 Reihenfolge... 2 Vorschlag für eine Ordnerstruktur... 3 Arbeit

Mehr

Die Dateiablage Der Weg zur Dateiablage

Die Dateiablage Der Weg zur Dateiablage Die Dateiablage In Ihrem Privatbereich haben Sie die Möglichkeit, Dateien verschiedener Formate abzulegen, zu sortieren, zu archivieren und in andere Dateiablagen der Plattform zu kopieren. In den Gruppen

Mehr

Web-Kürzel. Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter

Web-Kürzel. Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter 2 Inhaltsverzeichnis 1 Web-Kürzel 4 1.1 Einführung.......................................... 4 1.2 Web-Kürzel.........................................

Mehr

Große Übung Praktische Informatik 1

Große Übung Praktische Informatik 1 Große Übung Praktische Informatik 1 2005-12-08 fuessler@informatik.uni-mannheim.de http://www.informatik.uni-mannheim.de/pi4/people/fuessler 1: Announcements / Orga Weihnachtsklausur zählt als Übungsblatt,

Mehr

M. Graefenhan 2000-12-07. Übungen zu C. Blatt 3. Musterlösung

M. Graefenhan 2000-12-07. Übungen zu C. Blatt 3. Musterlösung M. Graefenhan 2000-12-07 Aufgabe Lösungsweg Übungen zu C Blatt 3 Musterlösung Schreiben Sie ein Programm, das die Häufigkeit von Zeichen in einem eingelesenen String feststellt. Benutzen Sie dazu ein zweidimensionales

Mehr

5. Abstrakte Klassen

5. Abstrakte Klassen 5. Abstrakte Klassen Beispiel 5. Abstrakte Klassen Angenommen, wir wollen die folgende Klassenhierarchie implementieren: Vogel Amsel Drossel Fink Peter Becker, Programiersprache Java FH Bonn-Rhein-Sieg,

Mehr

PHP Kurs Online Kurs Analysten Programmierer Web PHP

PHP Kurs Online Kurs Analysten Programmierer Web PHP PHP Kurs Online Kurs Analysten Programmierer Web PHP Akademie Domani info@akademiedomani.de Allgemeines Programm des Kurses PHP Modul 1 - Einführung und Installation PHP-Umgebung Erste Lerneinheit Introduzione

Mehr

Besonderheiten von C#

Besonderheiten von C# Besonderheiten von C# Wert- und Referenztypen int a, b; a = 3; b = a; a++; Debug.Assert( a==4 && b==3 &&!a.equals(b), "int ist doch kein Werttyp" ); RTyp ra, rb; ra = new RTyp(3); rb = ra; ra.inc(); Debug.Assert(

Mehr

Artikel Schnittstelle über CSV

Artikel Schnittstelle über CSV Artikel Schnittstelle über CSV Sie können Artikeldaten aus Ihrem EDV System in das NCFOX importieren, dies geschieht durch eine CSV Schnittstelle. Dies hat mehrere Vorteile: Zeitersparnis, die Karteikarte

Mehr

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version 1.0.0. 23. September 2015 - 1 -

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version 1.0.0. 23. September 2015 - 1 - Matrix42 Use Case - Sicherung und Rücksicherung persönlicher Version 1.0.0 23. September 2015-1 - Inhaltsverzeichnis 1 Einleitung 3 1.1 Beschreibung 3 1.2 Vorbereitung 3 1.3 Ziel 3 2 Use Case 4-2 - 1 Einleitung

Mehr

WPF Steuerelemente Listbox, ComboBox, ListView,

WPF Steuerelemente Listbox, ComboBox, ListView, WPF Steuerelemente Listbox, ComboBox, ListView, Dr. Beatrice Amrhein Überblick Einführung Listen ComboBox Tabellen 2 Einführung 3 Listen- und Tabellen-Elemente Listen und Tabellen-Elemente sind Steuerelemente,

Mehr

12. Dokumente Speichern und Drucken

12. Dokumente Speichern und Drucken 12. Dokumente Speichern und Drucken 12.1 Überblick Wie oft sollte man sein Dokument speichern? Nachdem Sie ein Word Dokument erstellt oder bearbeitet haben, sollten Sie es immer speichern. Sie sollten

Mehr

.NET Code schützen. Projekt.NET. Version 1.0

.NET Code schützen. Projekt.NET. Version 1.0 .NET Code schützen Projekt.NET Informationsmaterial zum Schützen des.net Codes Version 1.0 Autor: Status: Ablage: Empfänger: Seiten: D. Hoyer 1 / 6 Verteiler : Dokument1 Seite 1 von 1 Änderungsprotokoll

Mehr

Installation der SAS Foundation Software auf Windows

Installation der SAS Foundation Software auf Windows Installation der SAS Foundation Software auf Windows Der installierende Benutzer unter Windows muss Mitglied der lokalen Gruppe Administratoren / Administrators sein und damit das Recht besitzen, Software

Mehr

Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen. Alexander Schunk Marcel Teuber Henry Trobisch

Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen. Alexander Schunk Marcel Teuber Henry Trobisch Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen Alexander Schunk Henry Trobisch Inhalt 1. Vergleich der Unit-Tests... 2 2. Vergleich der Codeabdeckungs-Tests... 2 3. Vergleich

Mehr

Teil A Einführung in Microsoft Visual C# und Microsoft Visual Studio 2008 23

Teil A Einführung in Microsoft Visual C# und Microsoft Visual Studio 2008 23 Einleitung 13 Einführung 13 An wen sich dieses Buch richtet 13 Wegweiser für Ein- und Umsteiger 14 Konventionen und Features in diesem Buch 15 Konventionen 15 Weitere Features 16 Systemvoraussetzungen

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Objektorientierte Programmierung 1 Geschichte Dahl, Nygaard: Simula 67 (Algol 60 + Objektorientierung) Kay et al.: Smalltalk (erste rein-objektorientierte Sprache) Object Pascal, Objective C, C++ (wiederum

Mehr

Zählen von Objekten einer bestimmten Klasse

Zählen von Objekten einer bestimmten Klasse Zählen von Objekten einer bestimmten Klasse Ziel, Inhalt Zur Übung versuchen wir eine Klasse zu schreiben, mit der es möglich ist Objekte einer bestimmten Klasse zu zählen. Wir werden den ++ und den --

Mehr

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein. Schritt 1: Installation des Javacompilers JDK. Der erste Start mit Eclipse Bevor Sie den Java-Compiler installieren sollten Sie sich vergewissern, ob er eventuell schon installiert ist. Gehen sie wie folgt

Mehr

Windows Presentation Foundation (WPF) -Grundlagen -Steuerelemente. Dr. Beatrice Amrhein

Windows Presentation Foundation (WPF) -Grundlagen -Steuerelemente. Dr. Beatrice Amrhein Windows Presentation Foundation (WPF) -Grundlagen -Steuerelemente Dr. Beatrice Amrhein Überblick Die Architektur WPF Projekt erstellen Steuerelemente einfügen Eigenschaften von Steuerelementen ändern Nach

Mehr

Datensicherung. Beschreibung der Datensicherung

Datensicherung. Beschreibung der Datensicherung Datensicherung Mit dem Datensicherungsprogramm können Sie Ihre persönlichen Daten problemlos Sichern. Es ist möglich eine komplette Datensicherung durchzuführen, aber auch nur die neuen und geänderten

Mehr

Windows Server 2012 R2 Essentials & Hyper-V

Windows Server 2012 R2 Essentials & Hyper-V erklärt: Windows Server 2012 R2 Essentials & Hyper-V Windows Server 2012 R2 Essentials bietet gegenüber der Vorgängerversion die Möglichkeit, mit den Boardmitteln den Windows Server 2012 R2 Essentials

Mehr

4D Server v12 64-bit Version BETA VERSION

4D Server v12 64-bit Version BETA VERSION 4D Server v12 64-bit Version BETA VERSION 4D Server v12 unterstützt jetzt das Windows 64-bit Betriebssystem. Hauptvorteil der 64-bit Technologie ist die rundum verbesserte Performance der Anwendungen und

Mehr

Suche schlecht beschriftete Bilder mit Eigenen Abfragen

Suche schlecht beschriftete Bilder mit Eigenen Abfragen Suche schlecht beschriftete Bilder mit Eigenen Abfragen Ist die Bilderdatenbank über einen längeren Zeitraum in Benutzung, so steigt die Wahrscheinlichkeit für schlecht beschriftete Bilder 1. Insbesondere

Mehr

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005 Einführung in Java PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005 Gliederung 1. Was ist Java / Geschichte von Java 2. Prinzip der Plattformunabhängigkeit 3. Wie kommt man vom Quellcode zum Programm

Mehr

Zeichen bei Zahlen entschlüsseln

Zeichen bei Zahlen entschlüsseln Zeichen bei Zahlen entschlüsseln In diesem Kapitel... Verwendung des Zahlenstrahls Absolut richtige Bestimmung von absoluten Werten Operationen bei Zahlen mit Vorzeichen: Addieren, Subtrahieren, Multiplizieren

Mehr

KURZANLEITUNG CLOUD OBJECT STORAGE

KURZANLEITUNG CLOUD OBJECT STORAGE KURZANLEITUNG CLOUD OBJECT STORAGE Version 1.12 01.07.2014 SEITE _ 2 INHALTSVERZEICHNIS 1. Einleitung... Seite 03 2. Anmelden am Cloud&Heat Dashboard... Seite 04 3. Anlegen eines Containers... Seite 05

Mehr

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster Es gibt in Excel unter anderem die so genannten Suchfunktionen / Matrixfunktionen Damit können Sie Werte innerhalb eines bestimmten Bereichs suchen. Als Beispiel möchte ich die Funktion Sverweis zeigen.

Mehr

SANDBOXIE konfigurieren

SANDBOXIE konfigurieren SANDBOXIE konfigurieren für Webbrowser und E-Mail-Programme Dies ist eine kurze Anleitung für die grundlegenden folgender Programme: Webbrowser: Internet Explorer, Mozilla Firefox und Opera E-Mail-Programme:

Mehr

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck Javadoc Programmiermethodik Eva Zangerle Universität Innsbruck Überblick Einführung Java Ein erster Überblick Objektorientierung Vererbung und Polymorphismus Ausnahmebehandlung Pakete und Javadoc Spezielle

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags Pommes... Praktikum A 230 C 207 (Madeleine) F 112 F 113 (Kevin) E

Mehr

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Javakurs 2013 Objektorientierung

Javakurs 2013 Objektorientierung Javakurs 2013 Objektorientierung Objektorientierte Programmierung I Armelle Vérité 7 März 2013 Technische Universität Berlin This work is licensed under the Creative Commons Attribution-ShareAlike 3.0

Mehr

Source Code Konverter... 2. Online: (VB.net <-> C#)... 3. Kommerzielle Produkte (VB, C#, C++, Java)... 3. Code Nachbearbeitung in der Praxis...

Source Code Konverter... 2. Online: (VB.net <-> C#)... 3. Kommerzielle Produkte (VB, C#, C++, Java)... 3. Code Nachbearbeitung in der Praxis... Autor: Thomas Reinwart 2008-05-05 office@reinwart.com Inhalt Source Code Konverter... 2 Online: (VB.net C#)... 3 Kommerzielle Produkte (VB, C#, C++, Java)... 3 Code Nachbearbeitung in der Praxis...

Mehr

Software Engineering Interaktionsdiagramme

Software Engineering Interaktionsdiagramme Software Engineering Interaktionsdiagramme Prof. Adrian A. Müller, PMP, PSM 1, CSM Fachbereich Informatik und Mikrosystemtechnik 1 Nachrichtenaustausch Welche Nachrichten werden ausgetauscht? (Methodenaufrufe)

Mehr

Prinzipien Objektorientierter Programmierung

Prinzipien Objektorientierter Programmierung Prinzipien Objektorientierter Programmierung Valerian Wintner Inhaltsverzeichnis 1 Vorwort 1 2 Kapselung 1 3 Polymorphie 2 3.1 Dynamische Polymorphie...................... 2 3.2 Statische Polymorphie........................

Mehr

Studentische Lösung zum Übungsblatt Nr. 7

Studentische Lösung zum Übungsblatt Nr. 7 Studentische Lösung zum Übungsblatt Nr. 7 Aufgabe 1) Dynamische Warteschlange public class UltimateOrderQueue private Order[] inhalt; private int hinten; // zeigt auf erstes freies Element private int

Mehr

Datentypen: Enum, Array, Struct, Union

Datentypen: Enum, Array, Struct, Union Datentypen: Enum, Array, Struct, Union C-Kurs 2013, 2. Tutorium Freitagsrunde http://wiki.freitagsrunde.org 10. September 2013 This work is licensed under the Creative Commons Attribution-ShareAlike 3.0

Mehr

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf http://informatik.swoke.de. Seite 1 von 22

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf http://informatik.swoke.de. Seite 1 von 22 Kapitel 19 Vererbung, UML Seite 1 von 22 Vererbung - Neben der Datenabstraktion und der Datenkapselung ist die Vererbung ein weiteres Merkmal der OOP. - Durch Vererbung werden die Methoden und die Eigenschaften

Mehr

Java Kurs für Anfänger Einheit 5 Methoden

Java Kurs für Anfänger Einheit 5 Methoden Java Kurs für Anfänger Einheit 5 Methoden Ludwig-Maximilians-Universität München (Institut für Informatik: Programmierung und Softwaretechnik von Prof.Wirsing) 22. Juni 2009 Inhaltsverzeichnis Methoden

Mehr

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005 Einführung in die objektorientierte Programmierung mit Java Klausur am 19. Oktober 2005 Matrikelnummer: Nachname: Vorname: Semesteranzahl: Die Klausur besteht aus drei Frageblöcken zu den Inhalten der

Mehr

Technische Dokumentation SilentStatistikTool

Technische Dokumentation SilentStatistikTool Technische Dokumentation SilentStatistikTool Version 1.0 Marko Schröder 1115063 Inhalt Einleitung... 3 Klasse Program... 3 Klasse ArgumentHandler... 3 Bereitgestellte Variablen... 3 Bereitgestellte Methoden...

Mehr

SEMINAR Modifikation für die Nutzung des Community Builders

SEMINAR Modifikation für die Nutzung des Community Builders 20.04.2010 SEMINAR Modifikation für die Nutzung des Community Builders Step by Step Anleitung ecktion SEMINAR Modifikation für die Nutzung des Community Builders Step by Step Anleitung Bevor Sie loslegen

Mehr

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI Universität Osnabrück Drei-Schichten-Architektur 3 - Objektorientierte Programmierung in Java Vorlesung 6: 3-Schichten-Architektur Fachkonzept - GUI SS 2005 Prof. Dr. F.M. Thiesing, FH Dortmund Ein großer

Mehr

Anbindung an easybill.de

Anbindung an easybill.de Anbindung an easybill.de Stand: 14. Dezember 2011 2011 Virthos Systems GmbH www.pixtacy.de Einleitung Pixtacy verfügt ab Version 2.3 über eine Schnittstelle zu dem Online-Fakturierungsprogramm easybill.de.

Mehr

S TAND N OVEMBE R 2012 HANDBUCH DUDLE.ELK-WUE.DE T E R M I N A B S P R A C H E N I N D E R L A N D E S K I R C H E

S TAND N OVEMBE R 2012 HANDBUCH DUDLE.ELK-WUE.DE T E R M I N A B S P R A C H E N I N D E R L A N D E S K I R C H E S TAND N OVEMBE R 2012 HANDBUCH T E R M I N A B S P R A C H E N I N D E R L A N D E S K I R C H E Herausgeber Referat Informationstechnologie in der Landeskirche und im Oberkirchenrat Evangelischer Oberkirchenrat

Mehr

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek Programmieren I Dr. Klaus Höppner Hochschule Darmstadt Wintersemester 2008/2009 1 / 22 2 / 22 Strategie zum Entwurf von Klassen Beispiele Objektorientierte Sichtweise: Mit welchen Objekten habe ich es

Mehr

! " # $ " % & Nicki Wruck worldwidewruck 08.02.2006

!  # $  % & Nicki Wruck worldwidewruck 08.02.2006 !"# $ " %& Nicki Wruck worldwidewruck 08.02.2006 Wer kennt die Problematik nicht? Die.pst Datei von Outlook wird unübersichtlich groß, das Starten und Beenden dauert immer länger. Hat man dann noch die.pst

Mehr

Lizenzen auschecken. Was ist zu tun?

Lizenzen auschecken. Was ist zu tun? Use case Lizenzen auschecken Ihr Unternehmen hat eine Netzwerk-Commuterlizenz mit beispielsweise 4 Lizenzen. Am Freitag wollen Sie Ihren Laptop mit nach Hause nehmen, um dort am Wochenende weiter zu arbeiten.

Mehr

teischl.com Software Design & Services e.u. office@teischl.com www.teischl.com/booknkeep www.facebook.com/booknkeep

teischl.com Software Design & Services e.u. office@teischl.com www.teischl.com/booknkeep www.facebook.com/booknkeep teischl.com Software Design & Services e.u. office@teischl.com www.teischl.com/booknkeep www.facebook.com/booknkeep 1. Erstellen Sie ein neues Rechnungsformular Mit book n keep können Sie nun Ihre eigenen

Mehr

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken Dateiname: ecdl5_01_00_documentation_standard.doc Speicherdatum: 14.02.2005 ECDL 2003 Basic Modul 5 Datenbank - Grundlagen

Mehr

Einführung in die Programmierung

Einführung in die Programmierung Technische Universität München WS 2003/2004 Institut für Informatik Prof. Dr. Christoph Zenger Testklausur Einführung in die Programmierung Probeklausur Java (Lösungsvorschlag) 1 Die Klasse ArrayList In

Mehr

Bauteilattribute als Sachdaten anzeigen

Bauteilattribute als Sachdaten anzeigen Mit den speedikon Attributfiltern können Sie die speedikon Attribute eines Bauteils als MicroStation Sachdaten an die Elemente anhängen Inhalte Was ist ein speedikon Attribut?... 3 Eigene Attribute vergeben...

Mehr

Javakurs zu Informatik I. Henning Heitkötter

Javakurs zu Informatik I. Henning Heitkötter Javakurs zu Informatik I Arrays vergleichen Implementieren Sie folgende Methode, die prüft, ob die Elemente der beiden Arrays an jeder Position übereinstimmen: public static boolean identisch(int[] a,

Mehr

IT-Basics 2. DI Gerhard Fließ

IT-Basics 2. DI Gerhard Fließ IT-Basics 2 DI Gerhard Fließ Wer bin ich? DI Gerhard Fließ Telematik Studium an der TU Graz Softwareentwickler XiTrust www.xitrust.com www.tugraz.at Worum geht es? Objektorientierte Programmierung Konzepte

Mehr

Computeranwendung und Programmierung (CuP)

Computeranwendung und Programmierung (CuP) Computeranwendung und Programmierung (CuP) VO: Peter Auer (Informationstechnologie) UE: Norbert Seifter (Angewandet Mathematik) Organisatorisches (Vorlesung) Vorlesungszeiten Montag 11:15 12:45 Freitag

Mehr

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten In dem Virtuellen Seminarordner werden für die Teilnehmerinnen und Teilnehmer des Seminars alle für das Seminar wichtigen Informationen,

Mehr

Übung: Verwendung von Java-Threads

Übung: Verwendung von Java-Threads Übung: Verwendung von Java-Threads Ziel der Übung: Diese Übung dient dazu, den Umgang mit Threads in der Programmiersprache Java kennenzulernen. Ein einfaches Java-Programm, das Threads nutzt, soll zum

Mehr

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7 Java 7 Elmar Fuchs Grundlagen Programmierung 1. Ausgabe, Dezember 2011 JAV7 5 Java 7 - Grundlagen Programmierung 5 Kontrollstrukturen In diesem Kapitel erfahren Sie wie Sie die Ausführung von von Bedingungen

Mehr

VBA-Programmierung: Zusammenfassung

VBA-Programmierung: Zusammenfassung VBA-Programmierung: Zusammenfassung Programmiersprachen (Definition, Einordnung VBA) Softwareentwicklung-Phasen: 1. Spezifikation 2. Entwurf 3. Implementierung Datentypen (einfach, zusammengesetzt) Programmablaufsteuerung

Mehr

Java Virtual Machine (JVM) Bytecode

Java Virtual Machine (JVM) Bytecode Java Virtual Machine (JVM) durch Java-Interpreter (java) realisiert abstrakte Maschine = Softwareschicht zwischen Anwendung und Betriebssystem verantwortlich für Laden von Klassen, Ausführen des Bytecodes,

Mehr

Installation SQL- Server 2012 Single Node

Installation SQL- Server 2012 Single Node Installation SQL- Server 2012 Single Node Dies ist eine Installationsanleitung für den neuen SQL Server 2012. Es beschreibt eine Single Node Installation auf einem virtuellen Windows Server 2008 R2 mit

Mehr

Microsoft Visual C# 2008

Microsoft Visual C# 2008 John Sharp 13 Microsoft Visual C# 2008 Schritt für Schritt 13 13 14 15 15 16 16 17 17 17 21 22 22 23 25 26 II 40 51 Press 53 54 54 55 55 56 56 57 58 63 63 64 Inhaltsverzeichnis Einleitung 13 Einführung

Mehr

IAWWeb PDFManager. - Kurzanleitung -

IAWWeb PDFManager. - Kurzanleitung - IAWWeb PDFManager - Kurzanleitung - 1. Einleitung Dieses Dokument beschreibt kurz die grundlegenden Funktionen des PDFManager. Der PDF Manager dient zur Pflege des Dokumentenbestandes. Er kann über die

Mehr

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht:

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Beiträge erstellen in Joomla Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Abbildung 1 - Kontrollzentrum Von hier aus kann man zu verschiedene Einstellungen

Mehr

Folgende Einstellungen sind notwendig, damit die Kommunikation zwischen Server und Client funktioniert:

Folgende Einstellungen sind notwendig, damit die Kommunikation zwischen Server und Client funktioniert: Firewall für Lexware professional konfigurieren Inhaltsverzeichnis: 1. Allgemein... 1 2. Einstellungen... 1 3. Windows XP SP2 und Windows 2003 Server SP1 Firewall...1 4. Bitdefender 9... 5 5. Norton Personal

Mehr

SAMMEL DEINE IDENTITÄTEN::: NINA FRANK :: 727026 :: WINTERSEMESTER 08 09

SAMMEL DEINE IDENTITÄTEN::: NINA FRANK :: 727026 :: WINTERSEMESTER 08 09 SAMMEL DEINE IDENTITÄTEN::: :: IDEE :: Ich selbst habe viele verschiedene Benutzernamen und Passwörter und wenn ich mir diese nicht alle aufschreiben würde, würde ich alle durcheinander bringen oder welche

Mehr

Summenbildung in Bauteiltabellen mit If Then Abfrage

Summenbildung in Bauteiltabellen mit If Then Abfrage Summenbildung in Bauteiltabellen mit If Then Abfrage Die in Bauteiltabellen ausgelesenen Werte lassen sich in jeder Spalte als Summe berechnen. So können selbstverständlich die Flächen der in der Tabelle

Mehr

5.2 Neue Projekte erstellen

5.2 Neue Projekte erstellen 5.2 Neue Projekte erstellen Das Bearbeiten von bestehenden Projekten und Objekten ist ja nicht schlecht wie aber können Sie neue Objekte hinzufügen oder gar völlig neue Projekte erstellen? Die Antwort

Mehr

Microsoft Access 2013 Navigationsformular (Musterlösung)

Microsoft Access 2013 Navigationsformular (Musterlösung) Hochschulrechenzentrum Justus-Liebig-Universität Gießen Microsoft Access 2013 Navigationsformular (Musterlösung) Musterlösung zum Navigationsformular (Access 2013) Seite 1 von 5 Inhaltsverzeichnis Vorbemerkung...

Mehr

Schritt-Schritt-Anleitung zum mobilen PC mit Paragon Drive Copy 10 und VMware Player

Schritt-Schritt-Anleitung zum mobilen PC mit Paragon Drive Copy 10 und VMware Player PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Python SVN-Revision 12

Python SVN-Revision 12 Python SVN-Revision 12 Uwe Ziegenhagen 7. Januar 2012 Vorwort Dieses Skript erhebt keinen Anspruch auf Vollständigkeit oder Richtigkeit. Es wird geschrieben, um mir als Gedächtnisstütze für den Umgang

Mehr

Step by Step Webserver unter Windows Server 2003. von Christian Bartl

Step by Step Webserver unter Windows Server 2003. von Christian Bartl Step by Step Webserver unter Windows Server 2003 von Webserver unter Windows Server 2003 Um den WWW-Server-Dienst IIS (Internet Information Service) zu nutzen muss dieser zunächst installiert werden (wird

Mehr

Benutzerhandbuch. Leitfaden zur Benutzung der Anwendung für sicheren Dateitransfer.

Benutzerhandbuch. Leitfaden zur Benutzung der Anwendung für sicheren Dateitransfer. Benutzerhandbuch Leitfaden zur Benutzung der Anwendung für sicheren Dateitransfer. 1 Startseite Wenn Sie die Anwendung starten, können Sie zwischen zwei Möglichkeiten wählen 1) Sie können eine Datei für

Mehr

Hello World. Javakurs 2014, 1. Vorlesung. Sebastian Schuck. basierend auf der Vorlage von Arne Kappen. wiki.freitagsrunde.org. 3.

Hello World. Javakurs 2014, 1. Vorlesung. Sebastian Schuck. basierend auf der Vorlage von Arne Kappen. wiki.freitagsrunde.org. 3. Hello World Javakurs 2014, 1. Vorlesung Sebastian Schuck basierend auf der Vorlage von Arne Kappen wiki.freitagsrunde.org 3. März 2014 This work is licensed under the Creative Commons Attribution-ShareAlike

Mehr

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1 CMS.R. Bedienungsanleitung Modul Cron Revision 1 Copyright 10.09.2009 www.sruttloff.de CMS.R. - 1 - WOZU CRON...3 VERWENDUNG...3 EINSTELLUNGEN...5 TASK ERSTELLEN / BEARBEITEN...6 RECHTE...7 EREIGNISSE...7

Mehr