Lustiges in .Net

Dim converter As TypeConverter = TypeDescriptor.GetConverter(GetType(Long))

If Not converter.CanConvertFrom(GetType(Long)) then
    Return False
Else
    Return True
End If

Dieser Schnipsel zeigt eine lustige Eigenheit in .Net. Wenn man sich über den TypeDescriptor einen Converter für beispielsweise Long holt und diesen fragt, ob er in den selben Typ (Long) umwandeln kann, dann gibt die Funktion CanConvertFrom False zurück. Etwas seltsam, denn Konvertieren kann man das ja, bzw. einfach zuweisen ohne zu konvertieren. Ich finde diesen Rückgabewert etwas verwunderlich!

Advertisements

Entity Framework bremst Visual Studio aus

Screenshot des Programms Process Monitor

Seit ein paar Tagen öffnete sich mein Visual Studio WPF Designer (XAML View) nur noch nach einer langen Wartezeit, oder manchmal auch gar nicht. Endloses Warten, ohne Aussicht auf Besserung.
Nach mehreren langen Web-Such-Sessions fand ich heute den entscheidenden Hinweis. Man sollte doch mit dem Tool Process Montitor von Windows SysInternals mal nachsehen, was Visual Studio während der Ladezeit macht.

Kaum gelesen, schon war das Tool runtergeladen und lief. Das Tool ist verständlich und kann bei fremden Programmen wirklich viel helfen. Es gibt ein Fadenkreuz, welches man auf ein Fenster des zu beobachtenden Prozesses zieht. Anschließend sind die Meldungen so gefiltert, dass nur die Meldungen des gewünschten Prozesses zu sehen sind. Ich habe das Tool parallel laufen lassen und konnte relativ schnell eine interessante Beobachtung machen. Wie im Screenshot zu sehen führte devenv.exe (VS2010) ca. 30 UDP Send Operationen aus. Auffällig ist dabei, das man in der Spalte Path sehen kann, wie der Port entsprechend hochgezählt wird. 000000.000 ist der entfernte Rechnername inklusive Domain. Visual Studio scheint nach einem passenden Port zu suchen. Nach ca. 1 – 2 Minuten stellt Visual Studio diese Suche dann ein und öffnet wie gewünscht den Editor. Was war geschehen?

Der Titel des Artikels verrät die Antwort. Das Entity Framework ist schuld. Ich habe einen Datencontext, welcher seinen Connection-String per Convention over Configuration aus der app.config bekommt. Dabei entspricht der Schlüssel des ConnectionStrings dem Namen des Contextes. Dieser Context wird im ViewModelLocator ins ViewModel injiziert. Nun lädt Visual Studio das ViewModel durch den ViewModelLocator aber auch wenn der Editor geöffnet wird. Dabei läuft der Code aber nicht mit der app.config meiner Anwendung, sondern mit der von Visual Studio. Hierdurch ist keine passende Konfiguration vorhanden und das Entity Framework begibt sich auf die Suche. Dabei wird unter anderem der Portscan durchgeführt, der sehr zeitaufwändig ist.

Die Lösung des Problems ist das Mvvm Light Toolkit, welches ich schon einsetzte. Dieses beinhaltet die Property ViewModelBase.IsInDesignModeStatic, welche angibt, ob der Code gerade im Designer läuft. Im ViewModelLocator kann man dann reagieren und statt des Context des Entity Frameworks einfache Objektdaten übergeben. Voraussetzung hierfür ist die Einführung einer Schnittstelle, welche vom Entity Framework und den Objektdaten implementiert wird. Jetzt lädt der Designer wieder schnell!

Das gezeigte Verhalten kann natürlich auch in richtigen Anwendungen zum Ärgernis werden, wenn die Konfigurationsdatei beispielsweise fehlt. Bevor eine Fehlermeldung kommt, würde einige Zeit vergehen, in der das Entity Framework nach einem passenden Server sucht. Ich habe allerdings noch nicht im Quellcode nachgesehen, der ja mittlerweile als Open Source vorliegt. Dies werde ich bei Gelegenheit nachholen.

Windows 8 Metro Enterprise Apps

Metro wurde von Microsoft ganz klar für Consumer konzipiert. Es geht um Unterhaltung, um Spiele, um Nachrichten und das möglichst attraktiv.

Enterprise Apps stehen da zunächst etwas zurück. Obwohl es Wege geben wird Apps im Unternehmen zu installieren, ohne über den Store zu gehen, hat Metro einige Einschränkungen. Eine davon ist, dass Metro-Apps und Desktop-Applikationen nicht direkt miteinander kommunizieren können. (Beispielsweise per API) Und das es erstmal nicht möglich ist direkt auf SQL Server zuzugreifen.

Einen möglichen Weg zur Kommunikation habe ich eben erfolgreich getestet. Da die Metro-Apps Internetzugriff haben, können sie mit Webservices interagieren. Die gute Nachricht: Es ist möglich einen Webservice in einer Desktop-Applikation laufen zu lassen, welcher auf einen bestimmten Port horcht und diesen dann aus der Metro App heraus über localhost abzufragen. Dadurch können, wenn auch umständlich, Metro Apps mit Desktop-Apps kommunizieren. Auch reines TCP soll möglich sein, was noch performanter sein könnte.

Zum Test habe ich mir Node.js runtergeladen und das Beispiel der Webseite mit Node.js ausgeführt. Dies ist ein Webserver, der „Hello World“ zurückliefert. Anschließend habe ich eine neue Grid App in VS 2012 erzeugt und dort in einen der Event-Handler folgenden Code eingefügt:

Dim client As HttpClient = New HttpClient()
Dim s As String = Await client.GetStringAsync("http://127.0.0.1:1337")
Debug.WriteLine(s)

Wichtig ist dabei noch, dass der Event-Handler das Keyword Async bekommen muss, damit Await funktioniert. Der HttpClient befindet sich unter System.Net.Http.
Ergebnis war, dass „Hello World“ ausgegeben wurde. Die Türe zwischen Desktop-Applikationen und Metro steht also offen.

Von der Datenbank zur Oberfläche mit .NET Teil 1

Diese Serie konnte ich mangels Zeit noch nicht fortsetzen.
Deshalb möchte ich aber trotzdem diesen Teil veröffentlichen.
Wer Interesse am Source hat kann mir gerne schreiben.

Dies soll der erste Teil einer begleitenden Serie zu einer Artikel Serie auf Heise-Developer werden. In der Artikelserie „Von der Datenbank bis zur Oberfläche mit .NET“ wird der schichtweise Aufbau einer .NET-Anwendung dargestellt. Für mich zeigt diese Artikelserie ein Thema auf, dass für mich im Moment sehr relevant ist.

Der Original-Artikel verwendet den Model-First-Ansatz, um mit dem Entity Framework den Datenzugriff zu abstrahieren. Dadurch muss mit T4-Templates gearbeitet werden und es gibt, wie der Artikel erwähnt außerdem einen Fehler in der deutschen Version von Visual Studio, der einem das Leben schwer macht. Ein relativ neuer Ansatz ist Code-First, bei dem man nur Code schreibt. Daraus kann dann die Datenbank erstellt werden. Um keine Datenbankinstallation zu benötigen wird in diesem Beispiel Microsoft SQL Server Compact 4.0 verwendet. Die Datenbank wird vom Entity Framework erstellt. Außerdem wird das Beispiel in VB.Net erstellt, da sehr viele Beispiele im Internet in C# sind und wenige in VB.Net. Warum sollten die C#-Entwickler nicht auch mal einen Konverter benutzen. Dieser Artikel folgt der Struktur des Original-Artikels und beschreibt dabei die Unterschiede zwischen den Ansätzen.

WWWings_GO

Der Original-Artikel beginnt mit dem Klassenbibliotheksprojekt WWWings_GO. GO steht für Geschäftsobjekte. Die Abbildung im Original-Artikel zeigt den Aufbau sehr schön. Im Original wird nun das Datenmodell mit dem Designer von Visual Studio erzeugt. Für Code-First ist dies nicht notwendig. Hier werden einfache Objekte erstellt. Die Objekte müssen öffentliche Properties anbieten, welche später zu Datenbankfeldern werden. Verknüpfungen zwischen den Objekten werden ebenfalls durch einfache Properties erreicht. Für Beziehungen des Typs 1-zu-n und n-zu-m werden entsprechende Listen als Typ genutzt.
Für Werttypen, wie Date oder Integer, welche später in der Datenbank mit NULL belegt werden sollen, nutzt man den generischen Typ Nullable(Of T). Im Beispiel ist die Klasse Flug zu sehen.

Public Class Flug
    Public Property ID As Integer
    Public Property Abflugort As String
    Public Property Zielort As String
    Public Property Datum As Date
    Public Property Plaetze As Integer
    Public Property FreiePlaetze As Integer
    Public Property Passagiere As IList(Of Passagier)
    Public Property Pilot As Pilot

    Public ReadOnly Property Route() As String
        Get
            Return Me.Abflugort & " -> " & Me.Zielort
        End Get
    End Property
    Public Overrides Function ToString() As String
        Return "Flug #" & Me.ID & ": " & Me.Route & ": " & Me.FreiePlaetze & " von " & Me.Plaetze & " frei."
    End Function
End Class

Besonders interessant ist, dass diese Klassenbibliothek keine besonderen Abhängigkeiten hat. Weder das Entity Framework, noch SQL Server CE müssen von diesem Projekt aus referenziert werden. Die Objekte sind einfach und schnell zu verstehen. Der Original-Artikel erstellt sowohl Datenzugriff und Objekte in diesem Projekt und verschiebt sie danach mit einem Trick in die Datenzugriffsschicht. Mit Code-First ist kein Trick notwendig!

WWWings_DZS

Als nächstes wird die Klassenbibliothek WWWings_DZS erstellt. Diese bekommt Verweise auf das Entity Framework, System.Data.Entity und WWWings_GO. Die wichtigste Klasse für das Entity Framework ist WWWingsModellContext. Diese wurde im Vergleich zum Original etwas umbenannt. Statt …Container heißt die Klasse hier …Context. Die Klasse erbt von DbContext aus dem Namespace System.Data.Entity. Im Beispiel sind die wichtigsten Bestandteile der Klasse zu sehen und anschließend erklärt.

Public Class WWWingsModellContext
    Inherits DbContext

    Public Sub New()
        System.Data.Entity.Database.SetInitializer(Of WWWingsModellContext)(New DropCreateDatabaseIfModelChanges(Of WWWingsModellContext))
    End Sub

    Public Property Fluege As DbSet(Of Flug)
    Public Property Personen As DbSet(Of Person)
    Public Property Piloten As DbSet(Of Pilot)
    Public Property Passagiere As DbSet(Of Passagier)

    Protected Overrides Sub OnModelCreating(modelBuilder As System.Data.Entity.DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)
        modelBuilder.Conventions.Remove(Of Conventions.PluralizingTableNameConvention)()

        modelBuilder.Entity(Of Person).ToTable("Personen")
        modelBuilder.Entity(Of Flug).ToTable("Fluege")

        modelBuilder.Entity(Of Person)().Property(Function(p) p.ID).HasDatabaseGeneratedOption(ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)
        modelBuilder.Entity(Of Flug)().Property(Function(p) p.ID).HasDatabaseGeneratedOption(ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)
    End Sub
End Class

Die Properties vom Typ DbSet(Of T) stellen Zugriffspunkte auf die entsprechenden Klassen dar. Sie werden vom Entity Framework zur Laufzeit automatisch  mit passenden Instanzen versehen. Die Methode OnModelCreating ist dafür verantwortlich das Mapping zwischen Datenbank und Objekten zu erstellen. Viele Eigenschaften des Mappings werden über Konventionen automatisch festgelegt. Innerhalb dieser Methode können solche Konventionen deaktiviert werden und das Mapping kann beeinflusst werden. Hier wird mit durch den DbModelBuilder eine Fluent-API angeboten. Im Beispiel wird die Konvention Tabellennamen in den Plural zu setzen abgeschaltet, da die Namen deutsch sind und bis jetzt nur der englische Plural unterstützt wird. Anschließend werden den Klassen Flug und Person entsprechende Tabellennamen zugewiesen. Danach wird für die Properties mit dem Namen ID beider Klassen die Datenbankautomatik eingestellt. Personen bekommen automatisch einen Schlüssel, Flüge nicht.

Im Konstruktor der Klasse WWWingsModellContext wird der Datenbankinitialisierer gesetzt. Ab Version 4.3 wird eine Datenbankmigration unterstützt werden. In den aktuellen Versionen gehen die Daten der Datenbank verloren. Der gewählte Datenbankinitialisierer prüft mittels eines Hash-Wertes, ob sich das Modell geändert hat. Ist dies der Fall, wird die Datenbank gelöscht und eine neue, passend zum neuen Modell erstellt. Wenn keine Datenbank existert wird sie entsprechend angelegt. Für solch ein Beispielprojekt oder kleine Tools ist das eine schöne Option. Für große Software nicht. Hier sollte der Initialisierer auf Nothing gesetzt werden. Dies signalisiert dem Entity Framework, dass man selbst die Datenbank erstellt. Erstellt wird die Datenbank beim ersten Zugriff auf diese.

WWWings_GL

Die dritte Klassenbibliothek ist die Geschäftslogik, welche die folgenden Referenzen braucht: WWWings_GO, WWWings_DZS und EntityFramework.

…. to be continued! ….

 

Teilnahme an „Beherrsche die Maschine“

Ich habe das Programm Clipper für den Wettbewerb „Beherrsche die Maschine“ von Microsoft eingereicht. Clipper setzt sich zusammen aus Clipboard, da das Programm mit der Zwischenablage arbeitet und Flipper, weil das Logo ein Delphin ist.

Ich bin gespannt, ob eine Platzierung unter den Preisen drin ist, denn ich habe viel Mühe in das Projekt gesteckt.

Clipper bietet die Möglichkeit Aktionen auszuführen, die als Ein- und Ausgabe die Zwischenablage nutzen. Beispiele sind:

  • Zwischenablage anzeigen
    • Zeigt den Text, oder das aktuelle Bild in der Zwischenablage an.
    • Text kann bearbeitet und wieder in der Zwischenablage gespeichert werden.
  • Screenshot2File
    • Erstellt von jedem aktiven Monitor einen Screenshot und speichert ihn in einer Datei an einem zuvor ausgewählten Ort.
  • Bilder verkleinern
    • Verkleinert das Bild in der Zwischenablage auf einen zuvor eingestellten Wert.
    • Befinden sich mehrere Bilddateien in der Zwischenablage werden neue kleinere Bilddateien im gleichen Ordner angelegt.
  • Vorlesen
    • Liest den Text aus der Zwischenablage vor. (Nutzt die Windows-Sprachausgabe)
    • Momentan nur in Englisch.

Aufgabe war es mindestens ein Windows 7 Feature zu nutzen. die folgenden finden sich in Clipper:

  • Nutzung der Windows 7 Jumpliste zur Aktivierung der Aktionen
  • GlassOptik für die meisten Fenster der Anwendung und alternative Fenster, falls die Glassoptik nicht gewollt ist.
  • Benutzung der KnownFolders, einem Mechanismus um auch Orte wie den Desktop, oder Eigene Dateien zuzugreifen.

EDIT:

Leider habe ich nicht gewonnen. Trotzdem möchte ich das Programm hier zum Ausprobieren zur Verfügung stellen: … To be Uploaded….

Test der codierten UI

Als Student kann man tolle Programme ausprobieren. Ich wollte gerade einen „Test der codierten UI“, also einen aufgezeichneten Oberflächentest ausprobieren. Die Erstellung des Tests lief wunderbar, aber der generierte Test ließ sich nicht kompilieren. Ich habe eine weile gebraucht um zu verstehen, warum nicht. Eine Referenz konnte nicht aufgelöst werden, weshalb die Importe für diesen Test als fehlerhaft markiert wurden. Nach etwas suchen fand ich raus, dass diese GUI-Tests neu im .Net-Framework 4 sind.
Der Fehler war nun gefunden. In den Projekteinstellungen unter Kompilieren -> Erweiterte Kompilieroptionen war als Zielframework 3.5 angegeben, welches die Referenzen nicht besitzt. So einfach kann das manchmal sein.
Jetzt klappt es und sieht sehr nützlich aus. Demnächst kann ich evtl. Zeit sparen, indem ich Tests schreibe und ausführe anstatt manuell rumzuklickern.